diff options
author | 2021-05-27 20:27:21 +0200 | |
---|---|---|
committer | 2021-05-31 14:30:11 +0200 | |
commit | ecc583e22d4689e38a528a8bf841ba1ce58edd7b (patch) | |
tree | 3dead89bc612f40ced0d908ffda5099c58b0b8dd /drivers/gpu/drm/tegra/hub.c | |
parent | drm/tegra: hub: Fix YUV support (diff) | |
download | wireguard-linux-ecc583e22d4689e38a528a8bf841ba1ce58edd7b.tar.xz wireguard-linux-ecc583e22d4689e38a528a8bf841ba1ce58edd7b.zip |
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>
Diffstat (limited to '')
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 130 |
1 files changed, 125 insertions, 5 deletions
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 94e1ccfb6235..b910155f80c4 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -23,6 +23,8 @@ #include "dc.h" #include "plane.h" +#define NFB 24 + static const u32 tegra_shared_plane_formats[] = { DRM_FORMAT_ARGB1555, DRM_FORMAT_RGB565, @@ -292,6 +294,74 @@ static int tegra_shared_plane_set_owner(struct tegra_plane *plane, return 0; } +static void tegra_shared_plane_setup_scaler(struct tegra_plane *plane) +{ + static const unsigned int coeffs[192] = { + 0x00000000, 0x3c70e400, 0x3bb037e4, 0x0c51cc9c, + 0x00100001, 0x3bf0dbfa, 0x3d00f406, 0x3fe003ff, + 0x00300002, 0x3b80cbf5, 0x3da1040d, 0x3fb003fe, + 0x00400002, 0x3b20bff1, 0x3e511015, 0x3f9003fc, + 0x00500002, 0x3ad0b3ed, 0x3f21201d, 0x3f5003fb, + 0x00500003, 0x3aa0a3e9, 0x3ff13026, 0x3f2007f9, + 0x00500403, 0x3a7097e6, 0x00e1402f, 0x3ee007f7, + 0x00500403, 0x3a608be4, 0x01d14c38, 0x3ea00bf6, + 0x00500403, 0x3a507fe2, 0x02e15c42, 0x3e500ff4, + 0x00500402, 0x3a6073e1, 0x03f16c4d, 0x3e000ff2, + 0x00400402, 0x3a706be0, 0x05117858, 0x3db013f0, + 0x00300402, 0x3a905fe0, 0x06318863, 0x3d6017ee, + 0x00300402, 0x3ab057e0, 0x0771986e, 0x3d001beb, + 0x00200001, 0x3af04fe1, 0x08a1a47a, 0x3cb023e9, + 0x00100001, 0x3b2047e2, 0x09e1b485, 0x3c6027e7, + 0x00100000, 0x3b703fe2, 0x0b11c091, 0x3c002fe6, + 0x3f203800, 0x0391103f, 0x3ff0a014, 0x0811606c, + 0x3f2037ff, 0x0351083c, 0x03e11842, 0x3f203c00, + 0x3f302fff, 0x03010439, 0x04311c45, 0x3f104401, + 0x3f302fff, 0x02c0fc35, 0x04812448, 0x3f104802, + 0x3f4027ff, 0x0270f832, 0x04c1284b, 0x3f205003, + 0x3f4023ff, 0x0230f030, 0x0511304e, 0x3f205403, + 0x3f601fff, 0x01f0e82d, 0x05613451, 0x3f205c04, + 0x3f701bfe, 0x01b0e02a, 0x05a13c54, 0x3f306006, + 0x3f7017fe, 0x0170d827, 0x05f14057, 0x3f406807, + 0x3f8017ff, 0x0140d424, 0x0641445a, 0x3f406c08, + 0x3fa013ff, 0x0100cc22, 0x0681485d, 0x3f507409, + 0x3fa00fff, 0x00d0c41f, 0x06d14c60, 0x3f607c0b, + 0x3fc00fff, 0x0090bc1c, 0x07115063, 0x3f80840c, + 0x3fd00bff, 0x0070b41a, 0x07515465, 0x3f908c0e, + 0x3fe007ff, 0x0040b018, 0x07915868, 0x3fb0900f, + 0x3ff00400, 0x0010a816, 0x07d15c6a, 0x3fd09811, + 0x00a04c0e, 0x0460f442, 0x0240a827, 0x05c15859, + 0x0090440d, 0x0440f040, 0x0480fc43, 0x00b05010, + 0x0080400c, 0x0410ec3e, 0x04910044, 0x00d05411, + 0x0070380b, 0x03f0e83d, 0x04b10846, 0x00e05812, + 0x0060340a, 0x03d0e43b, 0x04d10c48, 0x00f06013, + 0x00503009, 0x03b0e039, 0x04e11449, 0x01106415, + 0x00402c08, 0x0390d838, 0x05011c4b, 0x01206c16, + 0x00302807, 0x0370d436, 0x0511204c, 0x01407018, + 0x00302406, 0x0340d034, 0x0531244e, 0x01507419, + 0x00202005, 0x0320cc32, 0x05412c50, 0x01707c1b, + 0x00101c04, 0x0300c431, 0x05613451, 0x0180801d, + 0x00101803, 0x02e0c02f, 0x05713853, 0x01a0881e, + 0x00101002, 0x02b0bc2d, 0x05814054, 0x01c08c20, + 0x00000c02, 0x02a0b82c, 0x05914455, 0x01e09421, + 0x00000801, 0x0280b02a, 0x05a14c57, 0x02009c23, + 0x00000400, 0x0260ac28, 0x05b15458, 0x0220a025, + }; + unsigned int ratio, row, column; + + for (ratio = 0; ratio <= 2; ratio++) { + for (row = 0; row <= 15; row++) { + for (column = 0; column <= 3; column++) { + unsigned int index = (ratio << 6) + (row << 2) + column; + u32 value; + + value = COEFF_INDEX(index) | COEFF_DATA(coeffs[index]); + tegra_plane_writel(plane, value, + DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF); + } + } + } +} + static void tegra_dc_assign_shared_plane(struct tegra_dc *dc, struct tegra_plane *plane) { @@ -337,6 +407,8 @@ static void tegra_dc_assign_shared_plane(struct tegra_dc *dc, value |= THREAD_GROUP_ENABLE; tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP); + tegra_shared_plane_setup_scaler(plane); + tegra_shared_plane_update(plane); tegra_shared_plane_activate(plane); } @@ -444,6 +516,18 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, host1x_client_suspend(&dc->client); } +static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out) +{ + u64 tmp, tmp1, tmp2; + + tmp = (u64)dfixed_trunc(in); + tmp2 = (u64)out; + tmp1 = (tmp << NFB) + (tmp2 >> 1); + do_div(tmp1, tmp2); + + return lower_32_bits(tmp1); +} + static void tegra_shared_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -454,10 +538,10 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, unsigned int zpos = new_state->normalized_zpos; struct drm_framebuffer *fb = new_state->fb; struct tegra_plane *p = to_tegra_plane(plane); + u32 value, min_width, bypass = 0; dma_addr_t base, addr_flag = 0; unsigned int bpc; bool yuv, planar; - u32 value; int err; /* rien ne va plus */ @@ -495,12 +579,48 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos); tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL); - /* bypass scaling */ + /* scaling */ + min_width = min(new_state->src_w >> 16, new_state->crtc_w); + + value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPC); + + if (min_width < MAX_PIXELS_5TAP444(value)) { + value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; + } else { + value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPE); + + if (min_width < MAX_PIXELS_2TAP444(value)) + value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2; + else + dev_err(dc->dev, "invalid minimum width: %u\n", min_width); + } + value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER); - value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS; - tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); + if (new_state->src_w != new_state->crtc_w << 16) { + fixed20_12 width = dfixed_init(new_state->src_w >> 16); + u32 incr = compute_phase_incr(width, new_state->crtc_w) & ~0x1; + u32 init = (1 << (NFB - 1)) + (incr >> 1); + + tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_HPHASE_INCR); + tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_H_START_PHASE); + } else { + bypass |= INPUT_SCALER_HBYPASS; + } + + if (new_state->src_h != new_state->crtc_h << 16) { + fixed20_12 height = dfixed_init(new_state->src_h >> 16); + u32 incr = compute_phase_incr(height, new_state->crtc_h) & ~0x1; + u32 init = (1 << (NFB - 1)) + (incr >> 1); + + tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_VPHASE_INCR); + tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_V_START_PHASE); + } else { + bypass |= INPUT_SCALER_VBYPASS; + } + + tegra_plane_writel(p, bypass, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); /* disable compression */ tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL); @@ -531,7 +651,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, value = WIN_ENABLE | COLOR_EXPAND; tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); - value = V_SIZE(new_state->crtc_h) | H_SIZE(new_state->crtc_w); + value = V_SIZE(new_state->src_h >> 16) | H_SIZE(new_state->src_w >> 16); tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE); tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI); |