]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/i915/intel_overlay.c
drm: Nuke fb->pixel_format
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / i915 / intel_overlay.c
CommitLineData
02e792fb
DV
1/*
2 * Copyright © 2009
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Daniel Vetter <daniel@ffwll.ch>
25 *
26 * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
27 */
760285e7
DH
28#include <drm/drmP.h>
29#include <drm/i915_drm.h>
02e792fb
DV
30#include "i915_drv.h"
31#include "i915_reg.h"
32#include "intel_drv.h"
5d723d7a 33#include "intel_frontbuffer.h"
02e792fb
DV
34
35/* Limits for overlay size. According to intel doc, the real limits are:
36 * Y width: 4095, UV width (planar): 2047, Y height: 2047,
37 * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
38 * the mininum of both. */
39#define IMAGE_MAX_WIDTH 2048
40#define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
41/* on 830 and 845 these large limits result in the card hanging */
42#define IMAGE_MAX_WIDTH_LEGACY 1024
43#define IMAGE_MAX_HEIGHT_LEGACY 1088
44
45/* overlay register definitions */
46/* OCMD register */
47#define OCMD_TILED_SURFACE (0x1<<19)
48#define OCMD_MIRROR_MASK (0x3<<17)
49#define OCMD_MIRROR_MODE (0x3<<17)
50#define OCMD_MIRROR_HORIZONTAL (0x1<<17)
51#define OCMD_MIRROR_VERTICAL (0x2<<17)
52#define OCMD_MIRROR_BOTH (0x3<<17)
53#define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
54#define OCMD_UV_SWAP (0x1<<14) /* YVYU */
55#define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
56#define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
57#define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
58#define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
59#define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
60#define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
61#define OCMD_YUV_422_PACKED (0x8<<10)
62#define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
63#define OCMD_YUV_420_PLANAR (0xc<<10)
64#define OCMD_YUV_422_PLANAR (0xd<<10)
65#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
66#define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
67#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
d7961364 68#define OCMD_BUF_TYPE_MASK (0x1<<5)
02e792fb
DV
69#define OCMD_BUF_TYPE_FRAME (0x0<<5)
70#define OCMD_BUF_TYPE_FIELD (0x1<<5)
71#define OCMD_TEST_MODE (0x1<<4)
72#define OCMD_BUFFER_SELECT (0x3<<2)
73#define OCMD_BUFFER0 (0x0<<2)
74#define OCMD_BUFFER1 (0x1<<2)
75#define OCMD_FIELD_SELECT (0x1<<2)
76#define OCMD_FIELD0 (0x0<<1)
77#define OCMD_FIELD1 (0x1<<1)
78#define OCMD_ENABLE (0x1<<0)
79
80/* OCONFIG register */
81#define OCONF_PIPE_MASK (0x1<<18)
82#define OCONF_PIPE_A (0x0<<18)
83#define OCONF_PIPE_B (0x1<<18)
84#define OCONF_GAMMA2_ENABLE (0x1<<16)
85#define OCONF_CSC_MODE_BT601 (0x0<<5)
86#define OCONF_CSC_MODE_BT709 (0x1<<5)
87#define OCONF_CSC_BYPASS (0x1<<4)
88#define OCONF_CC_OUT_8BIT (0x1<<3)
89#define OCONF_TEST_MODE (0x1<<2)
90#define OCONF_THREE_LINE_BUFFER (0x1<<0)
91#define OCONF_TWO_LINE_BUFFER (0x0<<0)
92
93/* DCLRKM (dst-key) register */
94#define DST_KEY_ENABLE (0x1<<31)
95#define CLK_RGB24_MASK 0x0
96#define CLK_RGB16_MASK 0x070307
97#define CLK_RGB15_MASK 0x070707
98#define CLK_RGB8I_MASK 0xffffff
99
100#define RGB16_TO_COLORKEY(c) \
101 (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
102#define RGB15_TO_COLORKEY(c) \
103 (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
104
105/* overlay flip addr flag */
106#define OFC_UPDATE 0x1
107
108/* polyphase filter coefficients */
109#define N_HORIZ_Y_TAPS 5
110#define N_VERT_Y_TAPS 3
111#define N_HORIZ_UV_TAPS 3
112#define N_VERT_UV_TAPS 3
113#define N_PHASES 17
114#define MAX_TAPS 5
115
116/* memory bufferd overlay registers */
117struct overlay_registers {
0206e353
AJ
118 u32 OBUF_0Y;
119 u32 OBUF_1Y;
120 u32 OBUF_0U;
121 u32 OBUF_0V;
122 u32 OBUF_1U;
123 u32 OBUF_1V;
124 u32 OSTRIDE;
125 u32 YRGB_VPH;
126 u32 UV_VPH;
127 u32 HORZ_PH;
128 u32 INIT_PHS;
129 u32 DWINPOS;
130 u32 DWINSZ;
131 u32 SWIDTH;
132 u32 SWIDTHSW;
133 u32 SHEIGHT;
134 u32 YRGBSCALE;
135 u32 UVSCALE;
136 u32 OCLRC0;
137 u32 OCLRC1;
138 u32 DCLRKV;
139 u32 DCLRKM;
140 u32 SCLRKVH;
141 u32 SCLRKVL;
142 u32 SCLRKEN;
143 u32 OCONFIG;
144 u32 OCMD;
145 u32 RESERVED1; /* 0x6C */
146 u32 OSTART_0Y;
147 u32 OSTART_1Y;
148 u32 OSTART_0U;
149 u32 OSTART_0V;
150 u32 OSTART_1U;
151 u32 OSTART_1V;
152 u32 OTILEOFF_0Y;
153 u32 OTILEOFF_1Y;
154 u32 OTILEOFF_0U;
155 u32 OTILEOFF_0V;
156 u32 OTILEOFF_1U;
157 u32 OTILEOFF_1V;
158 u32 FASTHSCALE; /* 0xA0 */
159 u32 UVSCALEV; /* 0xA4 */
160 u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
161 u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
162 u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
163 u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
164 u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
165 u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
166 u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
167 u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
168 u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
02e792fb
DV
169};
170
23f09ce3 171struct intel_overlay {
1ee8da6d 172 struct drm_i915_private *i915;
23f09ce3 173 struct intel_crtc *crtc;
9b3b7841
CW
174 struct i915_vma *vma;
175 struct i915_vma *old_vma;
209c2a5e
VS
176 bool active;
177 bool pfit_active;
23f09ce3 178 u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
ea9da4e4
CW
179 u32 color_key:24;
180 u32 color_key_enabled:1;
23f09ce3
CW
181 u32 brightness, contrast, saturation;
182 u32 old_xscale, old_yscale;
183 /* register access */
184 u32 flip_addr;
185 struct drm_i915_gem_object *reg_bo;
186 /* flip handling */
0d9bdd88 187 struct i915_gem_active last_flip;
23f09ce3 188};
02e792fb 189
75020bc1 190static struct overlay_registers __iomem *
8d74f656 191intel_overlay_map_regs(struct intel_overlay *overlay)
02e792fb 192{
1ee8da6d 193 struct drm_i915_private *dev_priv = overlay->i915;
75020bc1 194 struct overlay_registers __iomem *regs;
02e792fb 195
1ee8da6d 196 if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
00731155 197 regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
9bb2ff73 198 else
f7bbe788 199 regs = io_mapping_map_wc(&dev_priv->ggtt.mappable,
d8dab00d
CW
200 overlay->flip_addr,
201 PAGE_SIZE);
02e792fb 202
9bb2ff73 203 return regs;
8d74f656 204}
02e792fb 205
9bb2ff73 206static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
75020bc1 207 struct overlay_registers __iomem *regs)
8d74f656 208{
1ee8da6d 209 if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
9bb2ff73 210 io_mapping_unmap(regs);
02e792fb
DV
211}
212
0d9bdd88 213static void intel_overlay_submit_request(struct intel_overlay *overlay,
dad540ce 214 struct drm_i915_gem_request *req,
0d9bdd88 215 i915_gem_retire_fn retire)
02e792fb 216{
0d9bdd88
CW
217 GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
218 &overlay->i915->drm.struct_mutex));
219 overlay->last_flip.retire = retire;
220 i915_gem_active_set(&overlay->last_flip, req);
75289874 221 i915_add_request(req);
0d9bdd88 222}
acb868d3 223
0d9bdd88
CW
224static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
225 struct drm_i915_gem_request *req,
226 i915_gem_retire_fn retire)
227{
228 intel_overlay_submit_request(overlay, req, retire);
229 return i915_gem_active_retire(&overlay->last_flip,
230 &overlay->i915->drm.struct_mutex);
02e792fb
DV
231}
232
8e637178
CW
233static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
234{
235 struct drm_i915_private *dev_priv = overlay->i915;
3b3f1650 236 struct intel_engine_cs *engine = dev_priv->engine[RCS];
8e637178
CW
237
238 return i915_gem_request_alloc(engine, dev_priv->kernel_context);
239}
240
02e792fb
DV
241/* overlay needs to be disable in OCMD reg */
242static int intel_overlay_on(struct intel_overlay *overlay)
243{
1ee8da6d 244 struct drm_i915_private *dev_priv = overlay->i915;
dad540ce 245 struct drm_i915_gem_request *req;
7e37f889 246 struct intel_ring *ring;
02e792fb 247 int ret;
02e792fb 248
77589f56 249 WARN_ON(overlay->active);
1ee8da6d 250 WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
106dadac 251
8e637178 252 req = alloc_request(overlay);
26827088
DG
253 if (IS_ERR(req))
254 return PTR_ERR(req);
e1f99ce6 255
5fb9de1a 256 ret = intel_ring_begin(req, 4);
dad540ce 257 if (ret) {
aa9b7810 258 i915_add_request_no_flush(req);
dad540ce
JH
259 return ret;
260 }
261
1c7c4301
VS
262 overlay->active = true;
263
1dae2dfb 264 ring = req->ring;
b5321f30
CW
265 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
266 intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
267 intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
268 intel_ring_emit(ring, MI_NOOP);
269 intel_ring_advance(ring);
02e792fb 270
dad540ce 271 return intel_overlay_do_wait_request(overlay, req, NULL);
02e792fb
DV
272}
273
274/* overlay needs to be enabled in OCMD reg */
8dc5d147
CW
275static int intel_overlay_continue(struct intel_overlay *overlay,
276 bool load_polyphase_filter)
02e792fb 277{
1ee8da6d 278 struct drm_i915_private *dev_priv = overlay->i915;
dad540ce 279 struct drm_i915_gem_request *req;
7e37f889 280 struct intel_ring *ring;
02e792fb
DV
281 u32 flip_addr = overlay->flip_addr;
282 u32 tmp;
e1f99ce6 283 int ret;
02e792fb 284
77589f56 285 WARN_ON(!overlay->active);
02e792fb
DV
286
287 if (load_polyphase_filter)
288 flip_addr |= OFC_UPDATE;
289
290 /* check for underruns */
291 tmp = I915_READ(DOVSTA);
292 if (tmp & (1 << 17))
293 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
294
8e637178 295 req = alloc_request(overlay);
26827088
DG
296 if (IS_ERR(req))
297 return PTR_ERR(req);
acb868d3 298
5fb9de1a 299 ret = intel_ring_begin(req, 2);
dad540ce 300 if (ret) {
aa9b7810 301 i915_add_request_no_flush(req);
dad540ce
JH
302 return ret;
303 }
304
1dae2dfb 305 ring = req->ring;
b5321f30
CW
306 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
307 intel_ring_emit(ring, flip_addr);
308 intel_ring_advance(ring);
5a5a0c64 309
0d9bdd88 310 intel_overlay_submit_request(overlay, req, NULL);
bf7dc5b7
JH
311
312 return 0;
5a5a0c64
DV
313}
314
0d9bdd88
CW
315static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
316 struct drm_i915_gem_request *req)
5a5a0c64 317{
0d9bdd88
CW
318 struct intel_overlay *overlay =
319 container_of(active, typeof(*overlay), last_flip);
9b3b7841 320 struct i915_vma *vma;
5a5a0c64 321
9b3b7841
CW
322 vma = fetch_and_zero(&overlay->old_vma);
323 if (WARN_ON(!vma))
324 return;
0d9bdd88 325
9b3b7841
CW
326 i915_gem_track_fb(vma->obj, NULL,
327 INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
5a5a0c64 328
058d88c4 329 i915_gem_object_unpin_from_display_plane(vma);
9b3b7841 330 i915_vma_put(vma);
b303cf95 331}
03f77ea5 332
0d9bdd88
CW
333static void intel_overlay_off_tail(struct i915_gem_active *active,
334 struct drm_i915_gem_request *req)
b303cf95 335{
0d9bdd88
CW
336 struct intel_overlay *overlay =
337 container_of(active, typeof(*overlay), last_flip);
9b3b7841 338 struct i915_vma *vma;
02e792fb 339
b303cf95 340 /* never have the overlay hw on without showing a frame */
9b3b7841
CW
341 vma = fetch_and_zero(&overlay->vma);
342 if (WARN_ON(!vma))
77589f56 343 return;
02e792fb 344
058d88c4 345 i915_gem_object_unpin_from_display_plane(vma);
9b3b7841 346 i915_vma_put(vma);
03f77ea5 347
b303cf95
CW
348 overlay->crtc->overlay = NULL;
349 overlay->crtc = NULL;
209c2a5e 350 overlay->active = false;
02e792fb
DV
351}
352
353/* overlay needs to be disabled in OCMD reg */
ce453d81 354static int intel_overlay_off(struct intel_overlay *overlay)
02e792fb 355{
1ee8da6d 356 struct drm_i915_private *dev_priv = overlay->i915;
dad540ce 357 struct drm_i915_gem_request *req;
7e37f889 358 struct intel_ring *ring;
8dc5d147 359 u32 flip_addr = overlay->flip_addr;
e1f99ce6 360 int ret;
02e792fb 361
77589f56 362 WARN_ON(!overlay->active);
02e792fb
DV
363
364 /* According to intel docs the overlay hw may hang (when switching
365 * off) without loading the filter coeffs. It is however unclear whether
366 * this applies to the disabling of the overlay or to the switching off
367 * of the hw. Do it in both cases */
368 flip_addr |= OFC_UPDATE;
369
8e637178 370 req = alloc_request(overlay);
26827088
DG
371 if (IS_ERR(req))
372 return PTR_ERR(req);
acb868d3 373
5fb9de1a 374 ret = intel_ring_begin(req, 6);
dad540ce 375 if (ret) {
aa9b7810 376 i915_add_request_no_flush(req);
dad540ce
JH
377 return ret;
378 }
379
1dae2dfb 380 ring = req->ring;
02e792fb 381 /* wait for overlay to go idle */
b5321f30
CW
382 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
383 intel_ring_emit(ring, flip_addr);
384 intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
02e792fb 385 /* turn overlay off */
1ee8da6d 386 if (IS_I830(dev_priv)) {
a9193983
DV
387 /* Workaround: Don't disable the overlay fully, since otherwise
388 * it dies on the next OVERLAY_ON cmd. */
b5321f30
CW
389 intel_ring_emit(ring, MI_NOOP);
390 intel_ring_emit(ring, MI_NOOP);
391 intel_ring_emit(ring, MI_NOOP);
a9193983 392 } else {
b5321f30
CW
393 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
394 intel_ring_emit(ring, flip_addr);
395 intel_ring_emit(ring,
e2f80391 396 MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
a9193983 397 }
b5321f30 398 intel_ring_advance(ring);
02e792fb 399
0d9bdd88
CW
400 return intel_overlay_do_wait_request(overlay, req,
401 intel_overlay_off_tail);
12ca45fe
DV
402}
403
03f77ea5
DV
404/* recover from an interruption due to a signal
405 * We have to be careful not to repeat work forever an make forward progess. */
ce453d81 406static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
03f77ea5 407{
0d9bdd88
CW
408 return i915_gem_active_retire(&overlay->last_flip,
409 &overlay->i915->drm.struct_mutex);
03f77ea5
DV
410}
411
5a5a0c64
DV
412/* Wait for pending overlay flip and release old frame.
413 * Needs to be called before the overlay register are changed
8d74f656
CW
414 * via intel_overlay_(un)map_regs
415 */
02e792fb
DV
416static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
417{
1ee8da6d 418 struct drm_i915_private *dev_priv = overlay->i915;
02e792fb 419 int ret;
02e792fb 420
91c8a326 421 lockdep_assert_held(&dev_priv->drm.struct_mutex);
1362b776 422
5cd68c98
CW
423 /* Only wait if there is actually an old frame to release to
424 * guarantee forward progress.
425 */
9b3b7841 426 if (!overlay->old_vma)
03f77ea5
DV
427 return 0;
428
5cd68c98
CW
429 if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
430 /* synchronous slowpath */
dad540ce 431 struct drm_i915_gem_request *req;
7e37f889 432 struct intel_ring *ring;
dad540ce 433
8e637178 434 req = alloc_request(overlay);
26827088
DG
435 if (IS_ERR(req))
436 return PTR_ERR(req);
e1f99ce6 437
5fb9de1a 438 ret = intel_ring_begin(req, 2);
dad540ce 439 if (ret) {
aa9b7810 440 i915_add_request_no_flush(req);
dad540ce
JH
441 return ret;
442 }
443
1dae2dfb 444 ring = req->ring;
b5321f30 445 intel_ring_emit(ring,
e2f80391 446 MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
b5321f30
CW
447 intel_ring_emit(ring, MI_NOOP);
448 intel_ring_advance(ring);
5cd68c98 449
dad540ce 450 ret = intel_overlay_do_wait_request(overlay, req,
b303cf95 451 intel_overlay_release_old_vid_tail);
5cd68c98
CW
452 if (ret)
453 return ret;
0d9bdd88
CW
454 } else
455 intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL);
02e792fb
DV
456
457 return 0;
458}
459
1362b776
VS
460void intel_overlay_reset(struct drm_i915_private *dev_priv)
461{
462 struct intel_overlay *overlay = dev_priv->overlay;
463
464 if (!overlay)
465 return;
466
467 intel_overlay_release_old_vid(overlay);
468
1362b776
VS
469 overlay->old_xscale = 0;
470 overlay->old_yscale = 0;
471 overlay->crtc = NULL;
472 overlay->active = false;
473}
474
02e792fb
DV
475struct put_image_params {
476 int format;
477 short dst_x;
478 short dst_y;
479 short dst_w;
480 short dst_h;
481 short src_w;
482 short src_scan_h;
483 short src_scan_w;
484 short src_h;
485 short stride_Y;
486 short stride_UV;
487 int offset_Y;
488 int offset_U;
489 int offset_V;
490};
491
492static int packed_depth_bytes(u32 format)
493{
494 switch (format & I915_OVERLAY_DEPTH_MASK) {
722506f0
CW
495 case I915_OVERLAY_YUV422:
496 return 4;
497 case I915_OVERLAY_YUV411:
498 /* return 6; not implemented */
499 default:
500 return -EINVAL;
02e792fb
DV
501 }
502}
503
504static int packed_width_bytes(u32 format, short width)
505{
506 switch (format & I915_OVERLAY_DEPTH_MASK) {
722506f0
CW
507 case I915_OVERLAY_YUV422:
508 return width << 1;
509 default:
510 return -EINVAL;
02e792fb
DV
511 }
512}
513
514static int uv_hsubsampling(u32 format)
515{
516 switch (format & I915_OVERLAY_DEPTH_MASK) {
722506f0
CW
517 case I915_OVERLAY_YUV422:
518 case I915_OVERLAY_YUV420:
519 return 2;
520 case I915_OVERLAY_YUV411:
521 case I915_OVERLAY_YUV410:
522 return 4;
523 default:
524 return -EINVAL;
02e792fb
DV
525 }
526}
527
528static int uv_vsubsampling(u32 format)
529{
530 switch (format & I915_OVERLAY_DEPTH_MASK) {
722506f0
CW
531 case I915_OVERLAY_YUV420:
532 case I915_OVERLAY_YUV410:
533 return 2;
534 case I915_OVERLAY_YUV422:
535 case I915_OVERLAY_YUV411:
536 return 1;
537 default:
538 return -EINVAL;
02e792fb
DV
539 }
540}
541
1ee8da6d 542static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width)
02e792fb
DV
543{
544 u32 mask, shift, ret;
1ee8da6d 545 if (IS_GEN2(dev_priv)) {
02e792fb
DV
546 mask = 0x1f;
547 shift = 5;
a6c45cf0
CW
548 } else {
549 mask = 0x3f;
550 shift = 6;
02e792fb
DV
551 }
552 ret = ((offset + width + mask) >> shift) - (offset >> shift);
1ee8da6d 553 if (!IS_GEN2(dev_priv))
02e792fb 554 ret <<= 1;
0206e353 555 ret -= 1;
02e792fb
DV
556 return ret << 2;
557}
558
559static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
560 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
561 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
562 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
563 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
564 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
565 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
566 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
567 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
568 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
569 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
570 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
571 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
572 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
573 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
574 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
575 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
722506f0
CW
576 0xb000, 0x3000, 0x0800, 0x3000, 0xb000
577};
578
02e792fb
DV
579static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
580 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
581 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
582 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
583 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
584 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
585 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
586 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
587 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
722506f0
CW
588 0x3000, 0x0800, 0x3000
589};
02e792fb 590
75020bc1 591static void update_polyphase_filter(struct overlay_registers __iomem *regs)
02e792fb 592{
75020bc1
BW
593 memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
594 memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
595 sizeof(uv_static_hcoeffs));
02e792fb
DV
596}
597
598static bool update_scaling_factors(struct intel_overlay *overlay,
75020bc1 599 struct overlay_registers __iomem *regs,
02e792fb
DV
600 struct put_image_params *params)
601{
602 /* fixed point with a 12 bit shift */
603 u32 xscale, yscale, xscale_UV, yscale_UV;
604#define FP_SHIFT 12
605#define FRACT_MASK 0xfff
606 bool scale_changed = false;
607 int uv_hscale = uv_hsubsampling(params->format);
608 int uv_vscale = uv_vsubsampling(params->format);
609
610 if (params->dst_w > 1)
611 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
612 /(params->dst_w);
613 else
614 xscale = 1 << FP_SHIFT;
615
616 if (params->dst_h > 1)
617 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
618 /(params->dst_h);
619 else
620 yscale = 1 << FP_SHIFT;
621
622 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
722506f0
CW
623 xscale_UV = xscale/uv_hscale;
624 yscale_UV = yscale/uv_vscale;
625 /* make the Y scale to UV scale ratio an exact multiply */
626 xscale = xscale_UV * uv_hscale;
627 yscale = yscale_UV * uv_vscale;
02e792fb 628 /*} else {
722506f0
CW
629 xscale_UV = 0;
630 yscale_UV = 0;
631 }*/
02e792fb
DV
632
633 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
634 scale_changed = true;
635 overlay->old_xscale = xscale;
636 overlay->old_yscale = yscale;
637
75020bc1
BW
638 iowrite32(((yscale & FRACT_MASK) << 20) |
639 ((xscale >> FP_SHIFT) << 16) |
640 ((xscale & FRACT_MASK) << 3),
641 &regs->YRGBSCALE);
722506f0 642
75020bc1
BW
643 iowrite32(((yscale_UV & FRACT_MASK) << 20) |
644 ((xscale_UV >> FP_SHIFT) << 16) |
645 ((xscale_UV & FRACT_MASK) << 3),
646 &regs->UVSCALE);
722506f0 647
75020bc1
BW
648 iowrite32((((yscale >> FP_SHIFT) << 16) |
649 ((yscale_UV >> FP_SHIFT) << 0)),
650 &regs->UVSCALEV);
02e792fb
DV
651
652 if (scale_changed)
653 update_polyphase_filter(regs);
654
655 return scale_changed;
656}
657
658static void update_colorkey(struct intel_overlay *overlay,
75020bc1 659 struct overlay_registers __iomem *regs)
02e792fb 660{
1967b34d
VS
661 const struct drm_framebuffer *fb =
662 overlay->crtc->base.primary->fb;
02e792fb 663 u32 key = overlay->color_key;
ea9da4e4
CW
664 u32 flags;
665
666 flags = 0;
667 if (overlay->color_key_enabled)
668 flags |= DST_KEY_ENABLE;
6ba3ddd9 669
438b74a5 670 switch (fb->format->format) {
1967b34d 671 case DRM_FORMAT_C8:
ea9da4e4
CW
672 key = 0;
673 flags |= CLK_RGB8I_MASK;
6ba3ddd9 674 break;
1967b34d
VS
675 case DRM_FORMAT_XRGB1555:
676 key = RGB15_TO_COLORKEY(key);
677 flags |= CLK_RGB15_MASK;
6ba3ddd9 678 break;
1967b34d
VS
679 case DRM_FORMAT_RGB565:
680 key = RGB16_TO_COLORKEY(key);
681 flags |= CLK_RGB16_MASK;
682 break;
683 default:
ea9da4e4 684 flags |= CLK_RGB24_MASK;
6ba3ddd9 685 break;
02e792fb 686 }
ea9da4e4
CW
687
688 iowrite32(key, &regs->DCLRKV);
689 iowrite32(flags, &regs->DCLRKM);
02e792fb
DV
690}
691
692static u32 overlay_cmd_reg(struct put_image_params *params)
693{
694 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
695
696 if (params->format & I915_OVERLAY_YUV_PLANAR) {
697 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
722506f0
CW
698 case I915_OVERLAY_YUV422:
699 cmd |= OCMD_YUV_422_PLANAR;
700 break;
701 case I915_OVERLAY_YUV420:
702 cmd |= OCMD_YUV_420_PLANAR;
703 break;
704 case I915_OVERLAY_YUV411:
705 case I915_OVERLAY_YUV410:
706 cmd |= OCMD_YUV_410_PLANAR;
707 break;
02e792fb
DV
708 }
709 } else { /* YUV packed */
710 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
722506f0
CW
711 case I915_OVERLAY_YUV422:
712 cmd |= OCMD_YUV_422_PACKED;
713 break;
714 case I915_OVERLAY_YUV411:
715 cmd |= OCMD_YUV_411_PACKED;
716 break;
02e792fb
DV
717 }
718
719 switch (params->format & I915_OVERLAY_SWAP_MASK) {
722506f0
CW
720 case I915_OVERLAY_NO_SWAP:
721 break;
722 case I915_OVERLAY_UV_SWAP:
723 cmd |= OCMD_UV_SWAP;
724 break;
725 case I915_OVERLAY_Y_SWAP:
726 cmd |= OCMD_Y_SWAP;
727 break;
728 case I915_OVERLAY_Y_AND_UV_SWAP:
729 cmd |= OCMD_Y_AND_UV_SWAP;
730 break;
02e792fb
DV
731 }
732 }
733
734 return cmd;
735}
736
5fe82c5e 737static int intel_overlay_do_put_image(struct intel_overlay *overlay,
05394f39 738 struct drm_i915_gem_object *new_bo,
5fe82c5e 739 struct put_image_params *params)
02e792fb
DV
740{
741 int ret, tmp_width;
75020bc1 742 struct overlay_registers __iomem *regs;
02e792fb 743 bool scale_changed = false;
1ee8da6d 744 struct drm_i915_private *dev_priv = overlay->i915;
75020bc1 745 u32 swidth, swidthsw, sheight, ostride;
a071fa00 746 enum pipe pipe = overlay->crtc->pipe;
9b3b7841 747 struct i915_vma *vma;
02e792fb 748
91c8a326
CW
749 lockdep_assert_held(&dev_priv->drm.struct_mutex);
750 WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
02e792fb 751
02e792fb
DV
752 ret = intel_overlay_release_old_vid(overlay);
753 if (ret != 0)
754 return ret;
755
058d88c4 756 vma = i915_gem_object_pin_to_display_plane(new_bo, 0,
e6617330 757 &i915_ggtt_view_normal);
058d88c4
CW
758 if (IS_ERR(vma))
759 return PTR_ERR(vma);
9b3b7841 760
49ef5294 761 ret = i915_vma_put_fence(vma);
d9e86c0e
CW
762 if (ret)
763 goto out_unpin;
764
02e792fb 765 if (!overlay->active) {
75020bc1 766 u32 oconfig;
8d74f656 767 regs = intel_overlay_map_regs(overlay);
02e792fb
DV
768 if (!regs) {
769 ret = -ENOMEM;
770 goto out_unpin;
771 }
75020bc1 772 oconfig = OCONF_CC_OUT_8BIT;
1ee8da6d 773 if (IS_GEN4(dev_priv))
75020bc1 774 oconfig |= OCONF_CSC_MODE_BT709;
a071fa00 775 oconfig |= pipe == 0 ?
02e792fb 776 OCONF_PIPE_A : OCONF_PIPE_B;
75020bc1 777 iowrite32(oconfig, &regs->OCONFIG);
9bb2ff73 778 intel_overlay_unmap_regs(overlay, regs);
02e792fb
DV
779
780 ret = intel_overlay_on(overlay);
781 if (ret != 0)
782 goto out_unpin;
783 }
784
8d74f656 785 regs = intel_overlay_map_regs(overlay);
02e792fb
DV
786 if (!regs) {
787 ret = -ENOMEM;
788 goto out_unpin;
789 }
790
75020bc1
BW
791 iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
792 iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
02e792fb
DV
793
794 if (params->format & I915_OVERLAY_YUV_PACKED)
795 tmp_width = packed_width_bytes(params->format, params->src_w);
796 else
797 tmp_width = params->src_w;
798
75020bc1 799 swidth = params->src_w;
1ee8da6d 800 swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
75020bc1 801 sheight = params->src_h;
bde13ebd 802 iowrite32(i915_ggtt_offset(vma) + params->offset_Y, &regs->OBUF_0Y);
75020bc1 803 ostride = params->stride_Y;
02e792fb
DV
804
805 if (params->format & I915_OVERLAY_YUV_PLANAR) {
806 int uv_hscale = uv_hsubsampling(params->format);
807 int uv_vscale = uv_vsubsampling(params->format);
808 u32 tmp_U, tmp_V;
75020bc1 809 swidth |= (params->src_w/uv_hscale) << 16;
1ee8da6d 810 tmp_U = calc_swidthsw(dev_priv, params->offset_U,
722506f0 811 params->src_w/uv_hscale);
1ee8da6d 812 tmp_V = calc_swidthsw(dev_priv, params->offset_V,
722506f0 813 params->src_w/uv_hscale);
75020bc1
BW
814 swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
815 sheight |= (params->src_h/uv_vscale) << 16;
bde13ebd
CW
816 iowrite32(i915_ggtt_offset(vma) + params->offset_U,
817 &regs->OBUF_0U);
818 iowrite32(i915_ggtt_offset(vma) + params->offset_V,
819 &regs->OBUF_0V);
75020bc1 820 ostride |= params->stride_UV << 16;
02e792fb
DV
821 }
822
75020bc1
BW
823 iowrite32(swidth, &regs->SWIDTH);
824 iowrite32(swidthsw, &regs->SWIDTHSW);
825 iowrite32(sheight, &regs->SHEIGHT);
826 iowrite32(ostride, &regs->OSTRIDE);
827
02e792fb
DV
828 scale_changed = update_scaling_factors(overlay, regs, params);
829
830 update_colorkey(overlay, regs);
831
75020bc1 832 iowrite32(overlay_cmd_reg(params), &regs->OCMD);
02e792fb 833
9bb2ff73 834 intel_overlay_unmap_regs(overlay, regs);
02e792fb 835
8dc5d147
CW
836 ret = intel_overlay_continue(overlay, scale_changed);
837 if (ret)
838 goto out_unpin;
02e792fb 839
9b3b7841 840 i915_gem_track_fb(overlay->vma->obj, new_bo,
a071fa00
DV
841 INTEL_FRONTBUFFER_OVERLAY(pipe));
842
9b3b7841
CW
843 overlay->old_vma = overlay->vma;
844 overlay->vma = vma;
02e792fb 845
5748b6a1 846 intel_frontbuffer_flip(dev_priv, INTEL_FRONTBUFFER_OVERLAY(pipe));
f99d7069 847
02e792fb
DV
848 return 0;
849
850out_unpin:
058d88c4 851 i915_gem_object_unpin_from_display_plane(vma);
02e792fb
DV
852 return ret;
853}
854
ce453d81 855int intel_overlay_switch_off(struct intel_overlay *overlay)
02e792fb 856{
1ee8da6d 857 struct drm_i915_private *dev_priv = overlay->i915;
75020bc1 858 struct overlay_registers __iomem *regs;
5dcdbcb0 859 int ret;
02e792fb 860
91c8a326
CW
861 lockdep_assert_held(&dev_priv->drm.struct_mutex);
862 WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
02e792fb 863
ce453d81 864 ret = intel_overlay_recover_from_interrupt(overlay);
b303cf95
CW
865 if (ret != 0)
866 return ret;
9bedb974 867
02e792fb
DV
868 if (!overlay->active)
869 return 0;
870
02e792fb
DV
871 ret = intel_overlay_release_old_vid(overlay);
872 if (ret != 0)
873 return ret;
874
8d74f656 875 regs = intel_overlay_map_regs(overlay);
75020bc1 876 iowrite32(0, &regs->OCMD);
9bb2ff73 877 intel_overlay_unmap_regs(overlay, regs);
02e792fb 878
0d9bdd88 879 return intel_overlay_off(overlay);
02e792fb
DV
880}
881
882static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
883 struct intel_crtc *crtc)
884{
f7abfe8b 885 if (!crtc->active)
02e792fb
DV
886 return -EINVAL;
887
02e792fb 888 /* can't use the overlay with double wide pipe */
6e3c9717 889 if (crtc->config->double_wide)
02e792fb
DV
890 return -EINVAL;
891
892 return 0;
893}
894
895static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
896{
1ee8da6d 897 struct drm_i915_private *dev_priv = overlay->i915;
02e792fb 898 u32 pfit_control = I915_READ(PFIT_CONTROL);
446d2183 899 u32 ratio;
02e792fb
DV
900
901 /* XXX: This is not the same logic as in the xorg driver, but more in
446d2183
CW
902 * line with the intel documentation for the i965
903 */
1ee8da6d 904 if (INTEL_GEN(dev_priv) >= 4) {
0206e353 905 /* on i965 use the PGM reg to read out the autoscaler values */
a6c45cf0
CW
906 ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
907 } else {
446d2183
CW
908 if (pfit_control & VERT_AUTO_SCALE)
909 ratio = I915_READ(PFIT_AUTO_RATIOS);
02e792fb 910 else
446d2183
CW
911 ratio = I915_READ(PFIT_PGM_RATIOS);
912 ratio >>= PFIT_VERT_SCALE_SHIFT;
02e792fb
DV
913 }
914
915 overlay->pfit_vscale_ratio = ratio;
916}
917
918static int check_overlay_dst(struct intel_overlay *overlay,
919 struct drm_intel_overlay_put_image *rec)
920{
921 struct drm_display_mode *mode = &overlay->crtc->base.mode;
922
75c13993
DV
923 if (rec->dst_x < mode->hdisplay &&
924 rec->dst_x + rec->dst_width <= mode->hdisplay &&
925 rec->dst_y < mode->vdisplay &&
926 rec->dst_y + rec->dst_height <= mode->vdisplay)
02e792fb
DV
927 return 0;
928 else
929 return -EINVAL;
930}
931
932static int check_overlay_scaling(struct put_image_params *rec)
933{
934 u32 tmp;
935
936 /* downscaling limit is 8.0 */
937 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
938 if (tmp > 7)
939 return -EINVAL;
940 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
941 if (tmp > 7)
942 return -EINVAL;
943
944 return 0;
945}
946
1ee8da6d 947static int check_overlay_src(struct drm_i915_private *dev_priv,
02e792fb 948 struct drm_intel_overlay_put_image *rec,
05394f39 949 struct drm_i915_gem_object *new_bo)
02e792fb 950{
02e792fb
DV
951 int uv_hscale = uv_hsubsampling(rec->flags);
952 int uv_vscale = uv_vsubsampling(rec->flags);
8f28f54a
DC
953 u32 stride_mask;
954 int depth;
955 u32 tmp;
02e792fb
DV
956
957 /* check src dimensions */
1ee8da6d 958 if (IS_845G(dev_priv) || IS_I830(dev_priv)) {
722506f0 959 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
9f7c3f44 960 rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
02e792fb
DV
961 return -EINVAL;
962 } else {
722506f0 963 if (rec->src_height > IMAGE_MAX_HEIGHT ||
9f7c3f44 964 rec->src_width > IMAGE_MAX_WIDTH)
02e792fb
DV
965 return -EINVAL;
966 }
9f7c3f44 967
02e792fb 968 /* better safe than sorry, use 4 as the maximal subsampling ratio */
722506f0 969 if (rec->src_height < N_VERT_Y_TAPS*4 ||
9f7c3f44 970 rec->src_width < N_HORIZ_Y_TAPS*4)
02e792fb
DV
971 return -EINVAL;
972
a1efd14a 973 /* check alignment constraints */
02e792fb 974 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
722506f0
CW
975 case I915_OVERLAY_RGB:
976 /* not implemented */
977 return -EINVAL;
9f7c3f44 978
722506f0 979 case I915_OVERLAY_YUV_PACKED:
722506f0 980 if (uv_vscale != 1)
02e792fb 981 return -EINVAL;
9f7c3f44
CW
982
983 depth = packed_depth_bytes(rec->flags);
722506f0
CW
984 if (depth < 0)
985 return depth;
9f7c3f44 986
722506f0
CW
987 /* ignore UV planes */
988 rec->stride_UV = 0;
989 rec->offset_U = 0;
990 rec->offset_V = 0;
991 /* check pixel alignment */
992 if (rec->offset_Y % depth)
993 return -EINVAL;
994 break;
9f7c3f44 995
722506f0
CW
996 case I915_OVERLAY_YUV_PLANAR:
997 if (uv_vscale < 0 || uv_hscale < 0)
02e792fb 998 return -EINVAL;
722506f0
CW
999 /* no offset restrictions for planar formats */
1000 break;
9f7c3f44 1001
722506f0
CW
1002 default:
1003 return -EINVAL;
02e792fb
DV
1004 }
1005
1006 if (rec->src_width % uv_hscale)
1007 return -EINVAL;
1008
1009 /* stride checking */
1ee8da6d 1010 if (IS_I830(dev_priv) || IS_845G(dev_priv))
a1efd14a
CW
1011 stride_mask = 255;
1012 else
1013 stride_mask = 63;
02e792fb
DV
1014
1015 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1016 return -EINVAL;
1ee8da6d 1017 if (IS_GEN4(dev_priv) && rec->stride_Y < 512)
02e792fb
DV
1018 return -EINVAL;
1019
1020 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
9f7c3f44
CW
1021 4096 : 8192;
1022 if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
02e792fb
DV
1023 return -EINVAL;
1024
1025 /* check buffer dimensions */
1026 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
722506f0
CW
1027 case I915_OVERLAY_RGB:
1028 case I915_OVERLAY_YUV_PACKED:
1029 /* always 4 Y values per depth pixels */
1030 if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1031 return -EINVAL;
1032
1033 tmp = rec->stride_Y*rec->src_height;
05394f39 1034 if (rec->offset_Y + tmp > new_bo->base.size)
722506f0
CW
1035 return -EINVAL;
1036 break;
1037
1038 case I915_OVERLAY_YUV_PLANAR:
1039 if (rec->src_width > rec->stride_Y)
1040 return -EINVAL;
1041 if (rec->src_width/uv_hscale > rec->stride_UV)
1042 return -EINVAL;
1043
9f7c3f44 1044 tmp = rec->stride_Y * rec->src_height;
05394f39 1045 if (rec->offset_Y + tmp > new_bo->base.size)
722506f0 1046 return -EINVAL;
9f7c3f44
CW
1047
1048 tmp = rec->stride_UV * (rec->src_height / uv_vscale);
05394f39
CW
1049 if (rec->offset_U + tmp > new_bo->base.size ||
1050 rec->offset_V + tmp > new_bo->base.size)
722506f0
CW
1051 return -EINVAL;
1052 break;
02e792fb
DV
1053 }
1054
1055 return 0;
1056}
1057
e9e331a8
CW
1058/**
1059 * Return the pipe currently connected to the panel fitter,
1060 * or -1 if the panel fitter is not present or not in use
1061 */
1ee8da6d 1062static int intel_panel_fitter_pipe(struct drm_i915_private *dev_priv)
e9e331a8 1063{
e9e331a8
CW
1064 u32 pfit_control;
1065
1066 /* i830 doesn't have a panel fitter */
1ee8da6d
CW
1067 if (INTEL_GEN(dev_priv) <= 3 &&
1068 (IS_I830(dev_priv) || !IS_MOBILE(dev_priv)))
e9e331a8
CW
1069 return -1;
1070
1071 pfit_control = I915_READ(PFIT_CONTROL);
1072
1073 /* See if the panel fitter is in use */
1074 if ((pfit_control & PFIT_ENABLE) == 0)
1075 return -1;
1076
1077 /* 965 can place panel fitter on either pipe */
1ee8da6d 1078 if (IS_GEN4(dev_priv))
e9e331a8
CW
1079 return (pfit_control >> 29) & 0x3;
1080
1081 /* older chips can only use pipe 1 */
1082 return 1;
1083}
1084
1ee8da6d
CW
1085int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
1086 struct drm_file *file_priv)
02e792fb
DV
1087{
1088 struct drm_intel_overlay_put_image *put_image_rec = data;
fac5e23e 1089 struct drm_i915_private *dev_priv = to_i915(dev);
02e792fb 1090 struct intel_overlay *overlay;
7707e653 1091 struct drm_crtc *drmmode_crtc;
02e792fb 1092 struct intel_crtc *crtc;
05394f39 1093 struct drm_i915_gem_object *new_bo;
02e792fb
DV
1094 struct put_image_params *params;
1095 int ret;
1096
02e792fb
DV
1097 overlay = dev_priv->overlay;
1098 if (!overlay) {
1099 DRM_DEBUG("userspace bug: no overlay\n");
1100 return -ENODEV;
1101 }
1102
1103 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
a0e99e68 1104 drm_modeset_lock_all(dev);
02e792fb
DV
1105 mutex_lock(&dev->struct_mutex);
1106
ce453d81 1107 ret = intel_overlay_switch_off(overlay);
02e792fb
DV
1108
1109 mutex_unlock(&dev->struct_mutex);
a0e99e68 1110 drm_modeset_unlock_all(dev);
02e792fb
DV
1111
1112 return ret;
1113 }
1114
b14c5679 1115 params = kmalloc(sizeof(*params), GFP_KERNEL);
02e792fb
DV
1116 if (!params)
1117 return -ENOMEM;
1118
7707e653
RC
1119 drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id);
1120 if (!drmmode_crtc) {
915a428e
DC
1121 ret = -ENOENT;
1122 goto out_free;
1123 }
7707e653 1124 crtc = to_intel_crtc(drmmode_crtc);
02e792fb 1125
03ac0642
CW
1126 new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle);
1127 if (!new_bo) {
915a428e
DC
1128 ret = -ENOENT;
1129 goto out_free;
1130 }
02e792fb 1131
a0e99e68 1132 drm_modeset_lock_all(dev);
02e792fb
DV
1133 mutex_lock(&dev->struct_mutex);
1134
3e510a8e 1135 if (i915_gem_object_is_tiled(new_bo)) {
3b25b31f 1136 DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
d9e86c0e
CW
1137 ret = -EINVAL;
1138 goto out_unlock;
1139 }
1140
ce453d81 1141 ret = intel_overlay_recover_from_interrupt(overlay);
b303cf95
CW
1142 if (ret != 0)
1143 goto out_unlock;
03f77ea5 1144
02e792fb
DV
1145 if (overlay->crtc != crtc) {
1146 struct drm_display_mode *mode = &crtc->base.mode;
ce453d81 1147 ret = intel_overlay_switch_off(overlay);
02e792fb
DV
1148 if (ret != 0)
1149 goto out_unlock;
1150
1151 ret = check_overlay_possible_on_crtc(overlay, crtc);
1152 if (ret != 0)
1153 goto out_unlock;
1154
1155 overlay->crtc = crtc;
1156 crtc->overlay = overlay;
1157
e9e331a8
CW
1158 /* line too wide, i.e. one-line-mode */
1159 if (mode->hdisplay > 1024 &&
1ee8da6d 1160 intel_panel_fitter_pipe(dev_priv) == crtc->pipe) {
209c2a5e 1161 overlay->pfit_active = true;
02e792fb
DV
1162 update_pfit_vscale_ratio(overlay);
1163 } else
209c2a5e 1164 overlay->pfit_active = false;
02e792fb
DV
1165 }
1166
1167 ret = check_overlay_dst(overlay, put_image_rec);
1168 if (ret != 0)
1169 goto out_unlock;
1170
1171 if (overlay->pfit_active) {
1172 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
722506f0 1173 overlay->pfit_vscale_ratio);
02e792fb
DV
1174 /* shifting right rounds downwards, so add 1 */
1175 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
722506f0 1176 overlay->pfit_vscale_ratio) + 1;
02e792fb
DV
1177 } else {
1178 params->dst_y = put_image_rec->dst_y;
1179 params->dst_h = put_image_rec->dst_height;
1180 }
1181 params->dst_x = put_image_rec->dst_x;
1182 params->dst_w = put_image_rec->dst_width;
1183
1184 params->src_w = put_image_rec->src_width;
1185 params->src_h = put_image_rec->src_height;
1186 params->src_scan_w = put_image_rec->src_scan_width;
1187 params->src_scan_h = put_image_rec->src_scan_height;
722506f0
CW
1188 if (params->src_scan_h > params->src_h ||
1189 params->src_scan_w > params->src_w) {
02e792fb
DV
1190 ret = -EINVAL;
1191 goto out_unlock;
1192 }
1193
1ee8da6d 1194 ret = check_overlay_src(dev_priv, put_image_rec, new_bo);
02e792fb
DV
1195 if (ret != 0)
1196 goto out_unlock;
1197 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1198 params->stride_Y = put_image_rec->stride_Y;
1199 params->stride_UV = put_image_rec->stride_UV;
1200 params->offset_Y = put_image_rec->offset_Y;
1201 params->offset_U = put_image_rec->offset_U;
1202 params->offset_V = put_image_rec->offset_V;
1203
1204 /* Check scaling after src size to prevent a divide-by-zero. */
1205 ret = check_overlay_scaling(params);
1206 if (ret != 0)
1207 goto out_unlock;
1208
1209 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1210 if (ret != 0)
1211 goto out_unlock;
1212
1213 mutex_unlock(&dev->struct_mutex);
a0e99e68 1214 drm_modeset_unlock_all(dev);
02e792fb
DV
1215
1216 kfree(params);
1217
1218 return 0;
1219
1220out_unlock:
1221 mutex_unlock(&dev->struct_mutex);
a0e99e68 1222 drm_modeset_unlock_all(dev);
f0cd5182 1223 i915_gem_object_put(new_bo);
915a428e 1224out_free:
02e792fb
DV
1225 kfree(params);
1226
1227 return ret;
1228}
1229
1230static void update_reg_attrs(struct intel_overlay *overlay,
75020bc1 1231 struct overlay_registers __iomem *regs)
02e792fb 1232{
75020bc1
BW
1233 iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
1234 &regs->OCLRC0);
1235 iowrite32(overlay->saturation, &regs->OCLRC1);
02e792fb
DV
1236}
1237
1238static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1239{
1240 int i;
1241
1242 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1243 return false;
1244
1245 for (i = 0; i < 3; i++) {
722506f0 1246 if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
02e792fb
DV
1247 return false;
1248 }
1249
1250 return true;
1251}
1252
1253static bool check_gamma5_errata(u32 gamma5)
1254{
1255 int i;
1256
1257 for (i = 0; i < 3; i++) {
1258 if (((gamma5 >> i*8) & 0xff) == 0x80)
1259 return false;
1260 }
1261
1262 return true;
1263}
1264
1265static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1266{
722506f0
CW
1267 if (!check_gamma_bounds(0, attrs->gamma0) ||
1268 !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1269 !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1270 !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1271 !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1272 !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1273 !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
02e792fb 1274 return -EINVAL;
722506f0 1275
02e792fb
DV
1276 if (!check_gamma5_errata(attrs->gamma5))
1277 return -EINVAL;
722506f0 1278
02e792fb
DV
1279 return 0;
1280}
1281
1ee8da6d
CW
1282int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data,
1283 struct drm_file *file_priv)
02e792fb
DV
1284{
1285 struct drm_intel_overlay_attrs *attrs = data;
fac5e23e 1286 struct drm_i915_private *dev_priv = to_i915(dev);
02e792fb 1287 struct intel_overlay *overlay;
75020bc1 1288 struct overlay_registers __iomem *regs;
02e792fb
DV
1289 int ret;
1290
02e792fb
DV
1291 overlay = dev_priv->overlay;
1292 if (!overlay) {
1293 DRM_DEBUG("userspace bug: no overlay\n");
1294 return -ENODEV;
1295 }
1296
a0e99e68 1297 drm_modeset_lock_all(dev);
02e792fb
DV
1298 mutex_lock(&dev->struct_mutex);
1299
60fc332c 1300 ret = -EINVAL;
02e792fb 1301 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
60fc332c 1302 attrs->color_key = overlay->color_key;
02e792fb 1303 attrs->brightness = overlay->brightness;
60fc332c 1304 attrs->contrast = overlay->contrast;
02e792fb
DV
1305 attrs->saturation = overlay->saturation;
1306
1ee8da6d 1307 if (!IS_GEN2(dev_priv)) {
02e792fb
DV
1308 attrs->gamma0 = I915_READ(OGAMC0);
1309 attrs->gamma1 = I915_READ(OGAMC1);
1310 attrs->gamma2 = I915_READ(OGAMC2);
1311 attrs->gamma3 = I915_READ(OGAMC3);
1312 attrs->gamma4 = I915_READ(OGAMC4);
1313 attrs->gamma5 = I915_READ(OGAMC5);
1314 }
02e792fb 1315 } else {
60fc332c 1316 if (attrs->brightness < -128 || attrs->brightness > 127)
02e792fb 1317 goto out_unlock;
60fc332c 1318 if (attrs->contrast > 255)
02e792fb 1319 goto out_unlock;
60fc332c 1320 if (attrs->saturation > 1023)
02e792fb 1321 goto out_unlock;
02e792fb 1322
60fc332c
CW
1323 overlay->color_key = attrs->color_key;
1324 overlay->brightness = attrs->brightness;
1325 overlay->contrast = attrs->contrast;
1326 overlay->saturation = attrs->saturation;
02e792fb 1327
8d74f656 1328 regs = intel_overlay_map_regs(overlay);
02e792fb
DV
1329 if (!regs) {
1330 ret = -ENOMEM;
1331 goto out_unlock;
1332 }
1333
1334 update_reg_attrs(overlay, regs);
1335
9bb2ff73 1336 intel_overlay_unmap_regs(overlay, regs);
02e792fb
DV
1337
1338 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1ee8da6d 1339 if (IS_GEN2(dev_priv))
02e792fb 1340 goto out_unlock;
02e792fb
DV
1341
1342 if (overlay->active) {
1343 ret = -EBUSY;
1344 goto out_unlock;
1345 }
1346
1347 ret = check_gamma(attrs);
60fc332c 1348 if (ret)
02e792fb
DV
1349 goto out_unlock;
1350
1351 I915_WRITE(OGAMC0, attrs->gamma0);
1352 I915_WRITE(OGAMC1, attrs->gamma1);
1353 I915_WRITE(OGAMC2, attrs->gamma2);
1354 I915_WRITE(OGAMC3, attrs->gamma3);
1355 I915_WRITE(OGAMC4, attrs->gamma4);
1356 I915_WRITE(OGAMC5, attrs->gamma5);
1357 }
02e792fb 1358 }
ea9da4e4 1359 overlay->color_key_enabled = (attrs->flags & I915_OVERLAY_DISABLE_DEST_COLORKEY) == 0;
02e792fb 1360
60fc332c 1361 ret = 0;
02e792fb
DV
1362out_unlock:
1363 mutex_unlock(&dev->struct_mutex);
a0e99e68 1364 drm_modeset_unlock_all(dev);
02e792fb
DV
1365
1366 return ret;
1367}
1368
1ee8da6d 1369void intel_setup_overlay(struct drm_i915_private *dev_priv)
02e792fb 1370{
02e792fb 1371 struct intel_overlay *overlay;
05394f39 1372 struct drm_i915_gem_object *reg_bo;
75020bc1 1373 struct overlay_registers __iomem *regs;
058d88c4 1374 struct i915_vma *vma = NULL;
02e792fb
DV
1375 int ret;
1376
1ee8da6d 1377 if (!HAS_OVERLAY(dev_priv))
02e792fb
DV
1378 return;
1379
b14c5679 1380 overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
02e792fb
DV
1381 if (!overlay)
1382 return;
79d24273 1383
91c8a326 1384 mutex_lock(&dev_priv->drm.struct_mutex);
79d24273
CW
1385 if (WARN_ON(dev_priv->overlay))
1386 goto out_free;
1387
1ee8da6d 1388 overlay->i915 = dev_priv;
02e792fb 1389
f63a484c 1390 reg_bo = NULL;
1ee8da6d 1391 if (!OVERLAY_NEEDS_PHYSICAL(dev_priv))
91c8a326
CW
1392 reg_bo = i915_gem_object_create_stolen(&dev_priv->drm,
1393 PAGE_SIZE);
80405138 1394 if (reg_bo == NULL)
91c8a326 1395 reg_bo = i915_gem_object_create(&dev_priv->drm, PAGE_SIZE);
fe3db79b 1396 if (IS_ERR(reg_bo))
02e792fb 1397 goto out_free;
05394f39 1398 overlay->reg_bo = reg_bo;
02e792fb 1399
1ee8da6d 1400 if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) {
00731155 1401 ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE);
0206e353
AJ
1402 if (ret) {
1403 DRM_ERROR("failed to attach phys overlay regs\n");
1404 goto out_free_bo;
1405 }
00731155 1406 overlay->flip_addr = reg_bo->phys_handle->busaddr;
31578148 1407 } else {
058d88c4 1408 vma = i915_gem_object_ggtt_pin(reg_bo, NULL,
de895082 1409 0, PAGE_SIZE, PIN_MAPPABLE);
058d88c4 1410 if (IS_ERR(vma)) {
0206e353 1411 DRM_ERROR("failed to pin overlay register bo\n");
058d88c4 1412 ret = PTR_ERR(vma);
0206e353
AJ
1413 goto out_free_bo;
1414 }
bde13ebd 1415 overlay->flip_addr = i915_ggtt_offset(vma);
0ddc1289
CW
1416
1417 ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1418 if (ret) {
0206e353
AJ
1419 DRM_ERROR("failed to move overlay register bo into the GTT\n");
1420 goto out_unpin_bo;
1421 }
02e792fb
DV
1422 }
1423
1424 /* init all values */
1425 overlay->color_key = 0x0101fe;
ea9da4e4 1426 overlay->color_key_enabled = true;
02e792fb
DV
1427 overlay->brightness = -19;
1428 overlay->contrast = 75;
1429 overlay->saturation = 146;
1430
8d74f656 1431 regs = intel_overlay_map_regs(overlay);
02e792fb 1432 if (!regs)
79d24273 1433 goto out_unpin_bo;
02e792fb 1434
75020bc1 1435 memset_io(regs, 0, sizeof(struct overlay_registers));
02e792fb 1436 update_polyphase_filter(regs);
02e792fb
DV
1437 update_reg_attrs(overlay, regs);
1438
9bb2ff73 1439 intel_overlay_unmap_regs(overlay, regs);
02e792fb
DV
1440
1441 dev_priv->overlay = overlay;
91c8a326 1442 mutex_unlock(&dev_priv->drm.struct_mutex);
02e792fb
DV
1443 DRM_INFO("initialized overlay support\n");
1444 return;
1445
0ddc1289 1446out_unpin_bo:
058d88c4
CW
1447 if (vma)
1448 i915_vma_unpin(vma);
02e792fb 1449out_free_bo:
f8c417cd 1450 i915_gem_object_put(reg_bo);
02e792fb 1451out_free:
91c8a326 1452 mutex_unlock(&dev_priv->drm.struct_mutex);
02e792fb
DV
1453 kfree(overlay);
1454 return;
1455}
1456
1ee8da6d 1457void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
02e792fb 1458{
62cf4e6f
CW
1459 if (!dev_priv->overlay)
1460 return;
02e792fb 1461
62cf4e6f
CW
1462 /* The bo's should be free'd by the generic code already.
1463 * Furthermore modesetting teardown happens beforehand so the
1464 * hardware should be off already */
77589f56 1465 WARN_ON(dev_priv->overlay->active);
62cf4e6f 1466
f0cd5182 1467 i915_gem_object_put(dev_priv->overlay->reg_bo);
62cf4e6f 1468 kfree(dev_priv->overlay);
02e792fb 1469}
6ef3d427 1470
98a2f411
CW
1471#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
1472
6ef3d427
CW
1473struct intel_overlay_error_state {
1474 struct overlay_registers regs;
1475 unsigned long base;
1476 u32 dovsta;
1477 u32 isr;
1478};
1479
75020bc1 1480static struct overlay_registers __iomem *
c48c43e4 1481intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
3bd3c932 1482{
1ee8da6d 1483 struct drm_i915_private *dev_priv = overlay->i915;
75020bc1 1484 struct overlay_registers __iomem *regs;
3bd3c932 1485
1ee8da6d 1486 if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
75020bc1
BW
1487 /* Cast to make sparse happy, but it's wc memory anyway, so
1488 * equivalent to the wc io mapping on X86. */
1489 regs = (struct overlay_registers __iomem *)
00731155 1490 overlay->reg_bo->phys_handle->vaddr;
3bd3c932 1491 else
f7bbe788 1492 regs = io_mapping_map_atomic_wc(&dev_priv->ggtt.mappable,
da6ca034 1493 overlay->flip_addr);
3bd3c932
CW
1494
1495 return regs;
1496}
1497
1498static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
75020bc1 1499 struct overlay_registers __iomem *regs)
3bd3c932 1500{
1ee8da6d 1501 if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
c48c43e4 1502 io_mapping_unmap_atomic(regs);
3bd3c932
CW
1503}
1504
6ef3d427 1505struct intel_overlay_error_state *
c033666a 1506intel_overlay_capture_error_state(struct drm_i915_private *dev_priv)
6ef3d427 1507{
6ef3d427
CW
1508 struct intel_overlay *overlay = dev_priv->overlay;
1509 struct intel_overlay_error_state *error;
1510 struct overlay_registers __iomem *regs;
1511
1512 if (!overlay || !overlay->active)
1513 return NULL;
1514
1515 error = kmalloc(sizeof(*error), GFP_ATOMIC);
1516 if (error == NULL)
1517 return NULL;
1518
1519 error->dovsta = I915_READ(DOVSTA);
1520 error->isr = I915_READ(ISR);
da6ca034 1521 error->base = overlay->flip_addr;
6ef3d427
CW
1522
1523 regs = intel_overlay_map_regs_atomic(overlay);
1524 if (!regs)
1525 goto err;
1526
1527 memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
c48c43e4 1528 intel_overlay_unmap_regs_atomic(overlay, regs);
6ef3d427
CW
1529
1530 return error;
1531
1532err:
1533 kfree(error);
1534 return NULL;
1535}
1536
1537void
edc3d884
MK
1538intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
1539 struct intel_overlay_error_state *error)
6ef3d427 1540{
edc3d884
MK
1541 i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1542 error->dovsta, error->isr);
1543 i915_error_printf(m, " Register file at 0x%08lx:\n",
1544 error->base);
6ef3d427 1545
edc3d884 1546#define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x)
6ef3d427
CW
1547 P(OBUF_0Y);
1548 P(OBUF_1Y);
1549 P(OBUF_0U);
1550 P(OBUF_0V);
1551 P(OBUF_1U);
1552 P(OBUF_1V);
1553 P(OSTRIDE);
1554 P(YRGB_VPH);
1555 P(UV_VPH);
1556 P(HORZ_PH);
1557 P(INIT_PHS);
1558 P(DWINPOS);
1559 P(DWINSZ);
1560 P(SWIDTH);
1561 P(SWIDTHSW);
1562 P(SHEIGHT);
1563 P(YRGBSCALE);
1564 P(UVSCALE);
1565 P(OCLRC0);
1566 P(OCLRC1);
1567 P(DCLRKV);
1568 P(DCLRKM);
1569 P(SCLRKVH);
1570 P(SCLRKVL);
1571 P(SCLRKEN);
1572 P(OCONFIG);
1573 P(OCMD);
1574 P(OSTART_0Y);
1575 P(OSTART_1Y);
1576 P(OSTART_0U);
1577 P(OSTART_0V);
1578 P(OSTART_1U);
1579 P(OSTART_1V);
1580 P(OTILEOFF_0Y);
1581 P(OTILEOFF_1Y);
1582 P(OTILEOFF_0U);
1583 P(OTILEOFF_0V);
1584 P(OTILEOFF_1U);
1585 P(OTILEOFF_1V);
1586 P(FASTHSCALE);
1587 P(UVSCALEV);
1588#undef P
1589}
98a2f411
CW
1590
1591#endif