bfd8b07a295ea1e84c3b5099d7fb42fd20dc694f
[openwrt/staging/stintel.git] /
1 From 7135599a0b764e3579287763f160d82bb2901c45 Mon Sep 17 00:00:00 2001
2 From: Dom Cobley <popcornmix@gmail.com>
3 Date: Fri, 9 Apr 2021 15:00:40 +0100
4 Subject: [PATCH] vc4/drm: Handle fractional coordinates using the
5 phase field
6
7 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
8 ---
9 drivers/gpu/drm/vc4/vc4_plane.c | 61 ++++++++++++++++++++++++++++++---
10 1 file changed, 56 insertions(+), 5 deletions(-)
11
12 --- a/drivers/gpu/drm/vc4/vc4_plane.c
13 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
14 @@ -458,14 +458,47 @@ static void vc4_write_tpz(struct vc4_pla
15 VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
16 }
17
18 -static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
19 +/* phase magnitude bits */
20 +#define PHASE_BITS 6
21 +
22 +static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u32 xy, int channel)
23 {
24 - u32 scale = (1 << 16) * src / dst;
25 + u32 scale = src / dst;
26 + s32 offset, offset2;
27 + s32 phase;
28 +
29 + /* Start the phase at 1/2 pixel from the 1st pixel at src_x.
30 + 1/4 pixel for YUV. */
31 + if (channel) {
32 + /* the phase is relative to scale_src->x, so shift it for display list's x value */
33 + offset = (xy & 0x1ffff) >> (16 - PHASE_BITS) >> 1;
34 + offset += -(1 << PHASE_BITS >> 2);
35 + } else {
36 + /* the phase is relative to scale_src->x, so shift it for display list's x value */
37 + offset = (xy & 0xffff) >> (16 - PHASE_BITS);
38 + offset += -(1 << PHASE_BITS >> 1);
39 +
40 + /* This is a kludge to make sure the scaling factors are consitent with YUV's luma scaling.
41 + we lose 1bit precision because of this. */
42 + scale &= ~1;
43 + }
44 +
45 + /* There may be a also small error introduced by precision of scale.
46 + Add half of that as a compromise */
47 + offset2 = src - dst * scale;
48 + offset2 >>= 16 - PHASE_BITS;
49 + phase = offset + (offset2 >> 1);
50 +
51 + /* Ensure +ve values don't touch the sign bit, then truncate negative values */
52 + if (phase >= 1 << PHASE_BITS)
53 + phase = (1 << PHASE_BITS) - 1;
54 +
55 + phase &= SCALER_PPF_IPHASE_MASK;
56
57 vc4_dlist_write(vc4_state,
58 SCALER_PPF_AGC |
59 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
60 - VC4_SET_FIELD(0, SCALER_PPF_IPHASE));
61 + VC4_SET_FIELD(phase, SCALER_PPF_IPHASE));
62 }
63
64 static u32 vc4_lbm_size(struct drm_plane_state *state)
65 @@ -524,13 +557,13 @@ static void vc4_write_scaling_parameters
66 /* Ch0 H-PPF Word 0: Scaling Parameters */
67 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
68 vc4_write_ppf(vc4_state,
69 - vc4_state->src_w[channel], vc4_state->crtc_w);
70 + vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel);
71 }
72
73 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
74 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
75 vc4_write_ppf(vc4_state,
76 - vc4_state->src_h[channel], vc4_state->crtc_h);
77 + vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel);
78 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
79 }
80
81 @@ -978,6 +1011,24 @@ static int vc4_plane_mode_set(struct drm
82 return -EINVAL;
83 }
84
85 + /* fetch an extra pixel if we don't actually line up with the left edge. */
86 + if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16))
87 + width++;
88 +
89 + /* same for the right side */
90 + if (((vc4_state->src_x + vc4_state->src_w[0]) & 0xffff) &&
91 + vc4_state->src_x + vc4_state->src_w[0] < (state->fb->width << 16))
92 + width++;
93 +
94 + /* now for the top */
95 + if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16))
96 + height++;
97 +
98 + /* and the bottom */
99 + if (((vc4_state->src_y + vc4_state->src_h[0]) & 0xffff) &&
100 + vc4_state->src_y + vc4_state->src_h[0] < (state->fb->height << 16))
101 + height++;
102 +
103 /* Don't waste cycles mixing with plane alpha if the set alpha
104 * is opaque or there is no per-pixel alpha information.
105 * In any case we use the alpha property value as the fixed alpha.