]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.16.4/drm-i915-correctly-handle-limited-range-ycbcr-data-on-vlv-chv.patch
Fixes for 4.19
[thirdparty/kernel/stable-queue.git] / releases / 4.16.4 / drm-i915-correctly-handle-limited-range-ycbcr-data-on-vlv-chv.patch
1 From 5deae9191130db6b617c94fb261804597cf9b508 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
3 Date: Wed, 14 Feb 2018 21:23:23 +0200
4 Subject: drm/i915: Correctly handle limited range YCbCr data on VLV/CHV
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: Ville Syrjälä <ville.syrjala@linux.intel.com>
10
11 commit 5deae9191130db6b617c94fb261804597cf9b508 upstream.
12
13 Turns out the VLV/CHV fixed function sprite CSC expects full range
14 data as input. We've been feeding it limited range data to it all
15 along. To expand the data out to full range we'll use the color
16 correction registers (brightness, contrast, and saturation).
17
18 On CHV pipe B we were actually doing the right thing already because we
19 progammed the custom CSC matrix to do expect limited range input. Now
20 that well pre-expand the data out with the color correction unit, we
21 need to change the CSC matrix to operate with full range input instead.
22
23 This should make the sprite output of the other pipes match the sprite
24 output of pipe B reasonably well. Looking at the resulting pipe CRCs,
25 there can be a slight difference in the output, but as I don't know
26 the formula used by the fixed function CSC of the other pipes, I don't
27 think it's worth the effort to try to match the output exactly. It
28 might not even be possible due to difference in internal precision etc.
29
30 One slight caveat here is that the color correction registers are single
31 bufferred, so we should really be updating them during vblank, but we
32 still don't have a mechanism for that, so just toss in another FIXME.
33
34 v2: Rebase
35 v3: s/bri/brightness/ s/con/contrast/ (Shashank)
36 v4: Clarify the constants and math (Shashank)
37
38 Cc: Harry Wentland <harry.wentland@amd.com>
39 Cc: Daniel Vetter <daniel@ffwll.ch>
40 Cc: Daniel Stone <daniel@fooishbar.org>
41 Cc: Russell King - ARM Linux <linux@armlinux.org.uk>
42 Cc: Ilia Mirkin <imirkin@alum.mit.edu>
43 Cc: Hans Verkuil <hverkuil@xs4all.nl>
44 Cc: Shashank Sharma <shashank.sharma@intel.com>
45 Cc: Uma Shankar <uma.shankar@intel.com>
46 Cc: Jyri Sarha <jsarha@ti.com>
47 Cc: "Tang, Jun" <jun.tang@intel.com>
48 Reported-by: "Tang, Jun" <jun.tang@intel.com>
49 Cc: stable@vger.kernel.org
50 Fixes: 7f1f3851feb0 ("drm/i915: sprite support for ValleyView v4")
51 Reviewed-by: Shashank Sharma <shashank.sharma@intel.com>
52 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
53 Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-5-ville.syrjala@linux.intel.com
54 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
55
56 ---
57 drivers/gpu/drm/i915/i915_reg.h | 10 ++++
58 drivers/gpu/drm/i915/intel_sprite.c | 83 +++++++++++++++++++++++++++---------
59 2 files changed, 74 insertions(+), 19 deletions(-)
60
61 --- a/drivers/gpu/drm/i915/i915_reg.h
62 +++ b/drivers/gpu/drm/i915/i915_reg.h
63 @@ -6236,6 +6236,12 @@ enum {
64 #define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4)
65 #define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8)
66 #define SP_CONST_ALPHA_ENABLE (1<<31)
67 +#define _SPACLRC0 (VLV_DISPLAY_BASE + 0x721d0)
68 +#define SP_CONTRAST(x) ((x) << 18) /* u3.6 */
69 +#define SP_BRIGHTNESS(x) ((x) & 0xff) /* s8 */
70 +#define _SPACLRC1 (VLV_DISPLAY_BASE + 0x721d4)
71 +#define SP_SH_SIN(x) (((x) & 0x7ff) << 16) /* s4.7 */
72 +#define SP_SH_COS(x) (x) /* u3.7 */
73 #define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4)
74
75 #define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280)
76 @@ -6249,6 +6255,8 @@ enum {
77 #define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0)
78 #define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4)
79 #define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8)
80 +#define _SPBCLRC0 (VLV_DISPLAY_BASE + 0x722d0)
81 +#define _SPBCLRC1 (VLV_DISPLAY_BASE + 0x722d4)
82 #define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4)
83
84 #define _MMIO_VLV_SPR(pipe, plane_id, reg_a, reg_b) \
85 @@ -6265,6 +6273,8 @@ enum {
86 #define SPKEYMAXVAL(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
87 #define SPTILEOFF(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPATILEOFF, _SPBTILEOFF)
88 #define SPCONSTALPHA(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACONSTALPHA, _SPBCONSTALPHA)
89 +#define SPCLRC0(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC0, _SPBCLRC0)
90 +#define SPCLRC1(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC1, _SPBCLRC1)
91 #define SPGAMC(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAGAMC, _SPBGAMC)
92
93 /*
94 --- a/drivers/gpu/drm/i915/intel_sprite.c
95 +++ b/drivers/gpu/drm/i915/intel_sprite.c
96 @@ -346,44 +346,87 @@ skl_plane_get_hw_state(struct intel_plan
97 }
98
99 static void
100 -chv_update_csc(struct intel_plane *plane, uint32_t format)
101 +chv_update_csc(const struct intel_plane_state *plane_state)
102 {
103 + struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
104 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
105 + const struct drm_framebuffer *fb = plane_state->base.fb;
106 enum plane_id plane_id = plane->id;
107
108 /* Seems RGB data bypasses the CSC always */
109 - if (!format_is_yuv(format))
110 + if (!format_is_yuv(fb->format->format))
111 return;
112
113 /*
114 - * BT.601 limited range YCbCr -> full range RGB
115 + * BT.601 full range YCbCr -> full range RGB
116 *
117 - * |r| | 6537 4769 0| |cr |
118 - * |g| = |-3330 4769 -1605| x |y-64|
119 - * |b| | 0 4769 8263| |cb |
120 + * |r| | 5743 4096 0| |cr|
121 + * |g| = |-2925 4096 -1410| x |y |
122 + * |b| | 0 4096 7258| |cb|
123 *
124 - * Cb and Cr apparently come in as signed already, so no
125 - * need for any offset. For Y we need to remove the offset.
126 + * Cb and Cr apparently come in as signed already,
127 + * and we get full range data in on account of CLRC0/1
128 */
129 - I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64));
130 + I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
131 I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
132 I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
133
134 - I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537));
135 - I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0));
136 - I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769));
137 - I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0));
138 - I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263));
139 -
140 - I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64));
141 - I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
142 - I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
143 + I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4096) | SPCSC_C0(5743));
144 + I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-2925) | SPCSC_C0(0));
145 + I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1410) | SPCSC_C0(4096));
146 + I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4096) | SPCSC_C0(0));
147 + I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(7258));
148 +
149 + I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0));
150 + I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512));
151 + I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512));
152
153 I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
154 I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
155 I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
156 }
157
158 +#define SIN_0 0
159 +#define COS_0 1
160 +
161 +static void
162 +vlv_update_clrc(const struct intel_plane_state *plane_state)
163 +{
164 + struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
165 + struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
166 + const struct drm_framebuffer *fb = plane_state->base.fb;
167 + enum pipe pipe = plane->pipe;
168 + enum plane_id plane_id = plane->id;
169 + int contrast, brightness, sh_scale, sh_sin, sh_cos;
170 +
171 + if (format_is_yuv(fb->format->format)) {
172 + /*
173 + * Expand limited range to full range:
174 + * Contrast is applied first and is used to expand Y range.
175 + * Brightness is applied second and is used to remove the
176 + * offset from Y. Saturation/hue is used to expand CbCr range.
177 + */
178 + contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16);
179 + brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16);
180 + sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128);
181 + sh_sin = SIN_0 * sh_scale;
182 + sh_cos = COS_0 * sh_scale;
183 + } else {
184 + /* Pass-through everything. */
185 + contrast = 1 << 6;
186 + brightness = 0;
187 + sh_scale = 1 << 7;
188 + sh_sin = SIN_0 * sh_scale;
189 + sh_cos = COS_0 * sh_scale;
190 + }
191 +
192 + /* FIXME these register are single buffered :( */
193 + I915_WRITE_FW(SPCLRC0(pipe, plane_id),
194 + SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness));
195 + I915_WRITE_FW(SPCLRC1(pipe, plane_id),
196 + SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos));
197 +}
198 +
199 static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
200 const struct intel_plane_state *plane_state)
201 {
202 @@ -477,8 +520,10 @@ vlv_update_plane(struct intel_plane *pla
203
204 spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
205
206 + vlv_update_clrc(plane_state);
207 +
208 if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
209 - chv_update_csc(plane, fb->format->format);
210 + chv_update_csc(plane_state);
211
212 if (key->flags) {
213 I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value);