UPSTREAM: 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.

Change-Id: Ia64ca5ef66e0afcbb80db0c11e5e88af0017411d
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2545954
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Thierry Reding
2021-05-27 20:27:21 +02:00
committed by Laxman Dewangan
parent fbce3f1d95
commit dce2bcb225
2 changed files with 144 additions and 5 deletions

View File

@@ -24,6 +24,8 @@
#include "dc.h"
#include "plane.h"
#define NFB 24
static const u32 tegra_shared_plane_formats[] = {
DRM_FORMAT_ARGB1555,
DRM_FORMAT_RGB565,
@@ -293,6 +295,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)
{
@@ -338,6 +408,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);
}
@@ -456,6 +528,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,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
struct drm_atomic_state *state)
@@ -472,10 +556,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 */
@@ -517,12 +601,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);
@@ -553,7 +673,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);