1235783Skib/*
2235783Skib * Copyright �� 2009
3235783Skib *
4235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
5235783Skib * copy of this software and associated documentation files (the "Software"),
6235783Skib * to deal in the Software without restriction, including without limitation
7235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8235783Skib * and/or sell copies of the Software, and to permit persons to whom the
9235783Skib * Software is furnished to do so, subject to the following conditions:
10235783Skib *
11235783Skib * The above copyright notice and this permission notice (including the next
12235783Skib * paragraph) shall be included in all copies or substantial portions of the
13235783Skib * Software.
14235783Skib *
15235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20235783Skib * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21235783Skib * SOFTWARE.
22235783Skib *
23235783Skib * Authors:
24235783Skib *    Daniel Vetter <daniel@ffwll.ch>
25235783Skib *
26235783Skib * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
27235783Skib */
28235783Skib
29235783Skib#include <sys/cdefs.h>
30235783Skib__FBSDID("$FreeBSD$");
31235783Skib
32235783Skib#include <dev/drm2/drmP.h>
33235783Skib#include <dev/drm2/drm.h>
34235783Skib#include <dev/drm2/i915/i915_drm.h>
35235783Skib#include <dev/drm2/i915/i915_drv.h>
36235783Skib#include <dev/drm2/i915/i915_reg.h>
37235783Skib#include <dev/drm2/i915/intel_drv.h>
38235783Skib
39235783Skib/* Limits for overlay size. According to intel doc, the real limits are:
40235783Skib * Y width: 4095, UV width (planar): 2047, Y height: 2047,
41235783Skib * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
42235783Skib * the mininum of both.  */
43235783Skib#define IMAGE_MAX_WIDTH		2048
44235783Skib#define IMAGE_MAX_HEIGHT	2046 /* 2 * 1023 */
45235783Skib/* on 830 and 845 these large limits result in the card hanging */
46235783Skib#define IMAGE_MAX_WIDTH_LEGACY	1024
47235783Skib#define IMAGE_MAX_HEIGHT_LEGACY	1088
48235783Skib
49235783Skib/* overlay register definitions */
50235783Skib/* OCMD register */
51235783Skib#define OCMD_TILED_SURFACE	(0x1<<19)
52235783Skib#define OCMD_MIRROR_MASK	(0x3<<17)
53235783Skib#define OCMD_MIRROR_MODE	(0x3<<17)
54235783Skib#define OCMD_MIRROR_HORIZONTAL	(0x1<<17)
55235783Skib#define OCMD_MIRROR_VERTICAL	(0x2<<17)
56235783Skib#define OCMD_MIRROR_BOTH	(0x3<<17)
57235783Skib#define OCMD_BYTEORDER_MASK	(0x3<<14) /* zero for YUYV or FOURCC YUY2 */
58235783Skib#define OCMD_UV_SWAP		(0x1<<14) /* YVYU */
59235783Skib#define OCMD_Y_SWAP		(0x2<<14) /* UYVY or FOURCC UYVY */
60235783Skib#define OCMD_Y_AND_UV_SWAP	(0x3<<14) /* VYUY */
61235783Skib#define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
62235783Skib#define OCMD_RGB_888		(0x1<<10) /* not in i965 Intel docs */
63235783Skib#define OCMD_RGB_555		(0x2<<10) /* not in i965 Intel docs */
64235783Skib#define OCMD_RGB_565		(0x3<<10) /* not in i965 Intel docs */
65235783Skib#define OCMD_YUV_422_PACKED	(0x8<<10)
66235783Skib#define OCMD_YUV_411_PACKED	(0x9<<10) /* not in i965 Intel docs */
67235783Skib#define OCMD_YUV_420_PLANAR	(0xc<<10)
68235783Skib#define OCMD_YUV_422_PLANAR	(0xd<<10)
69235783Skib#define OCMD_YUV_410_PLANAR	(0xe<<10) /* also 411 */
70235783Skib#define OCMD_TVSYNCFLIP_PARITY	(0x1<<9)
71235783Skib#define OCMD_TVSYNCFLIP_ENABLE	(0x1<<7)
72235783Skib#define OCMD_BUF_TYPE_MASK	(0x1<<5)
73235783Skib#define OCMD_BUF_TYPE_FRAME	(0x0<<5)
74235783Skib#define OCMD_BUF_TYPE_FIELD	(0x1<<5)
75235783Skib#define OCMD_TEST_MODE		(0x1<<4)
76235783Skib#define OCMD_BUFFER_SELECT	(0x3<<2)
77235783Skib#define OCMD_BUFFER0		(0x0<<2)
78235783Skib#define OCMD_BUFFER1		(0x1<<2)
79235783Skib#define OCMD_FIELD_SELECT	(0x1<<2)
80235783Skib#define OCMD_FIELD0		(0x0<<1)
81235783Skib#define OCMD_FIELD1		(0x1<<1)
82235783Skib#define OCMD_ENABLE		(0x1<<0)
83235783Skib
84235783Skib/* OCONFIG register */
85235783Skib#define OCONF_PIPE_MASK		(0x1<<18)
86235783Skib#define OCONF_PIPE_A		(0x0<<18)
87235783Skib#define OCONF_PIPE_B		(0x1<<18)
88235783Skib#define OCONF_GAMMA2_ENABLE	(0x1<<16)
89235783Skib#define OCONF_CSC_MODE_BT601	(0x0<<5)
90235783Skib#define OCONF_CSC_MODE_BT709	(0x1<<5)
91235783Skib#define OCONF_CSC_BYPASS	(0x1<<4)
92235783Skib#define OCONF_CC_OUT_8BIT	(0x1<<3)
93235783Skib#define OCONF_TEST_MODE		(0x1<<2)
94235783Skib#define OCONF_THREE_LINE_BUFFER	(0x1<<0)
95235783Skib#define OCONF_TWO_LINE_BUFFER	(0x0<<0)
96235783Skib
97235783Skib/* DCLRKM (dst-key) register */
98235783Skib#define DST_KEY_ENABLE		(0x1<<31)
99235783Skib#define CLK_RGB24_MASK		0x0
100235783Skib#define CLK_RGB16_MASK		0x070307
101235783Skib#define CLK_RGB15_MASK		0x070707
102235783Skib#define CLK_RGB8I_MASK		0xffffff
103235783Skib
104235783Skib#define RGB16_TO_COLORKEY(c) \
105235783Skib	(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
106235783Skib#define RGB15_TO_COLORKEY(c) \
107235783Skib	(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
108235783Skib
109235783Skib/* overlay flip addr flag */
110235783Skib#define OFC_UPDATE		0x1
111235783Skib
112235783Skib/* polyphase filter coefficients */
113235783Skib#define N_HORIZ_Y_TAPS          5
114235783Skib#define N_VERT_Y_TAPS           3
115235783Skib#define N_HORIZ_UV_TAPS         3
116235783Skib#define N_VERT_UV_TAPS          3
117235783Skib#define N_PHASES                17
118235783Skib#define MAX_TAPS                5
119235783Skib
120235783Skib/* memory bufferd overlay registers */
121235783Skibstruct overlay_registers {
122235783Skib	u32 OBUF_0Y;
123235783Skib	u32 OBUF_1Y;
124235783Skib	u32 OBUF_0U;
125235783Skib	u32 OBUF_0V;
126235783Skib	u32 OBUF_1U;
127235783Skib	u32 OBUF_1V;
128235783Skib	u32 OSTRIDE;
129235783Skib	u32 YRGB_VPH;
130235783Skib	u32 UV_VPH;
131235783Skib	u32 HORZ_PH;
132235783Skib	u32 INIT_PHS;
133235783Skib	u32 DWINPOS;
134235783Skib	u32 DWINSZ;
135235783Skib	u32 SWIDTH;
136235783Skib	u32 SWIDTHSW;
137235783Skib	u32 SHEIGHT;
138235783Skib	u32 YRGBSCALE;
139235783Skib	u32 UVSCALE;
140235783Skib	u32 OCLRC0;
141235783Skib	u32 OCLRC1;
142235783Skib	u32 DCLRKV;
143235783Skib	u32 DCLRKM;
144235783Skib	u32 SCLRKVH;
145235783Skib	u32 SCLRKVL;
146235783Skib	u32 SCLRKEN;
147235783Skib	u32 OCONFIG;
148235783Skib	u32 OCMD;
149235783Skib	u32 RESERVED1; /* 0x6C */
150235783Skib	u32 OSTART_0Y;
151235783Skib	u32 OSTART_1Y;
152235783Skib	u32 OSTART_0U;
153235783Skib	u32 OSTART_0V;
154235783Skib	u32 OSTART_1U;
155235783Skib	u32 OSTART_1V;
156235783Skib	u32 OTILEOFF_0Y;
157235783Skib	u32 OTILEOFF_1Y;
158235783Skib	u32 OTILEOFF_0U;
159235783Skib	u32 OTILEOFF_0V;
160235783Skib	u32 OTILEOFF_1U;
161235783Skib	u32 OTILEOFF_1V;
162235783Skib	u32 FASTHSCALE; /* 0xA0 */
163235783Skib	u32 UVSCALEV; /* 0xA4 */
164235783Skib	u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
165235783Skib	u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
166235783Skib	u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
167235783Skib	u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
168235783Skib	u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
169235783Skib	u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
170235783Skib	u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
171235783Skib	u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
172235783Skib	u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
173235783Skib};
174235783Skib
175235783Skibstruct intel_overlay {
176235783Skib	struct drm_device *dev;
177235783Skib	struct intel_crtc *crtc;
178235783Skib	struct drm_i915_gem_object *vid_bo;
179235783Skib	struct drm_i915_gem_object *old_vid_bo;
180235783Skib	int active;
181235783Skib	int pfit_active;
182235783Skib	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
183235783Skib	u32 color_key;
184235783Skib	u32 brightness, contrast, saturation;
185235783Skib	u32 old_xscale, old_yscale;
186235783Skib	/* register access */
187235783Skib	u32 flip_addr;
188235783Skib	struct drm_i915_gem_object *reg_bo;
189235783Skib	/* flip handling */
190235783Skib	uint32_t last_flip_req;
191235783Skib	void (*flip_tail)(struct intel_overlay *);
192235783Skib};
193235783Skib
194235783Skibstatic struct overlay_registers *
195235783Skibintel_overlay_map_regs(struct intel_overlay *overlay)
196235783Skib{
197235783Skib	struct overlay_registers *regs;
198235783Skib
199235783Skib	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) {
200235783Skib		regs = overlay->reg_bo->phys_obj->handle->vaddr;
201235783Skib	} else {
202235783Skib		regs = pmap_mapdev_attr(overlay->dev->agp->base +
203235783Skib		    overlay->reg_bo->gtt_offset, PAGE_SIZE,
204235783Skib		    PAT_WRITE_COMBINING);
205235783Skib	}
206235783Skib	return (regs);
207235783Skib}
208235783Skib
209235783Skibstatic void intel_overlay_unmap_regs(struct intel_overlay *overlay,
210235783Skib				     struct overlay_registers *regs)
211235783Skib{
212235783Skib	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
213235783Skib		pmap_unmapdev((vm_offset_t)regs, PAGE_SIZE);
214235783Skib}
215235783Skib
216235783Skibstatic int intel_overlay_do_wait_request(struct intel_overlay *overlay,
217235783Skib					 struct drm_i915_gem_request *request,
218235783Skib					 void (*tail)(struct intel_overlay *))
219235783Skib{
220235783Skib	struct drm_device *dev = overlay->dev;
221235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
222235783Skib	int ret;
223235783Skib
224235783Skib	KASSERT(!overlay->last_flip_req, ("Overlay already has flip req"));
225235783Skib	ret = i915_add_request(LP_RING(dev_priv), NULL, request);
226235783Skib	if (ret) {
227235783Skib		free(request, DRM_I915_GEM);
228235783Skib		return ret;
229235783Skib	}
230235783Skib	overlay->last_flip_req = request->seqno;
231235783Skib	overlay->flip_tail = tail;
232235783Skib	ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
233235783Skib				true);
234235783Skib	if (ret)
235235783Skib		return ret;
236235783Skib
237235783Skib	overlay->last_flip_req = 0;
238235783Skib	return 0;
239235783Skib}
240235783Skib
241235783Skib/* Workaround for i830 bug where pipe a must be enable to change control regs */
242235783Skibstatic int
243235783Skibi830_activate_pipe_a(struct drm_device *dev)
244235783Skib{
245235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
246235783Skib	struct intel_crtc *crtc;
247235783Skib	struct drm_crtc_helper_funcs *crtc_funcs;
248235783Skib	struct drm_display_mode vesa_640x480 = {
249235783Skib		DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
250235783Skib			 752, 800, 0, 480, 489, 492, 525, 0,
251235783Skib			 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
252235783Skib	}, *mode;
253235783Skib
254235783Skib	crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
255235783Skib	if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
256235783Skib		return 0;
257235783Skib
258235783Skib	/* most i8xx have pipe a forced on, so don't trust dpms mode */
259235783Skib	if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE)
260235783Skib		return 0;
261235783Skib
262235783Skib	crtc_funcs = crtc->base.helper_private;
263235783Skib	if (crtc_funcs->dpms == NULL)
264235783Skib		return 0;
265235783Skib
266235783Skib	DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
267235783Skib
268235783Skib	mode = drm_mode_duplicate(dev, &vesa_640x480);
269235783Skib	drm_mode_set_crtcinfo(mode, 0);
270235783Skib	if (!drm_crtc_helper_set_mode(&crtc->base, mode,
271235783Skib				       crtc->base.x, crtc->base.y,
272235783Skib				       crtc->base.fb))
273235783Skib		return 0;
274235783Skib
275235783Skib	crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
276235783Skib	return 1;
277235783Skib}
278235783Skib
279235783Skibstatic void
280235783Skibi830_deactivate_pipe_a(struct drm_device *dev)
281235783Skib{
282235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
283235783Skib	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
284235783Skib	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
285235783Skib
286235783Skib	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
287235783Skib}
288235783Skib
289235783Skib/* overlay needs to be disable in OCMD reg */
290235783Skibstatic int intel_overlay_on(struct intel_overlay *overlay)
291235783Skib{
292235783Skib	struct drm_device *dev = overlay->dev;
293235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
294235783Skib	struct drm_i915_gem_request *request;
295235783Skib	int pipe_a_quirk = 0;
296235783Skib	int ret;
297235783Skib
298235783Skib	KASSERT(!overlay->active, ("Overlay is active"));
299235783Skib	overlay->active = 1;
300235783Skib
301235783Skib	if (IS_I830(dev)) {
302235783Skib		pipe_a_quirk = i830_activate_pipe_a(dev);
303235783Skib		if (pipe_a_quirk < 0)
304235783Skib			return pipe_a_quirk;
305235783Skib	}
306235783Skib
307235783Skib	request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
308235783Skib
309235783Skib	ret = BEGIN_LP_RING(4);
310235783Skib	if (ret) {
311235783Skib		free(request, DRM_I915_GEM);
312235783Skib		goto out;
313235783Skib	}
314235783Skib
315235783Skib	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
316235783Skib	OUT_RING(overlay->flip_addr | OFC_UPDATE);
317235783Skib	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
318235783Skib	OUT_RING(MI_NOOP);
319235783Skib	ADVANCE_LP_RING();
320235783Skib
321235783Skib	ret = intel_overlay_do_wait_request(overlay, request, NULL);
322235783Skibout:
323235783Skib	if (pipe_a_quirk)
324235783Skib		i830_deactivate_pipe_a(dev);
325235783Skib
326235783Skib	return ret;
327235783Skib}
328235783Skib
329235783Skib/* overlay needs to be enabled in OCMD reg */
330235783Skibstatic int intel_overlay_continue(struct intel_overlay *overlay,
331235783Skib				  bool load_polyphase_filter)
332235783Skib{
333235783Skib	struct drm_device *dev = overlay->dev;
334235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
335235783Skib	struct drm_i915_gem_request *request;
336235783Skib	u32 flip_addr = overlay->flip_addr;
337235783Skib	u32 tmp;
338235783Skib	int ret;
339235783Skib
340235783Skib	KASSERT(overlay->active, ("Overlay not active"));
341235783Skib
342235783Skib	request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
343235783Skib
344235783Skib	if (load_polyphase_filter)
345235783Skib		flip_addr |= OFC_UPDATE;
346235783Skib
347235783Skib	/* check for underruns */
348235783Skib	tmp = I915_READ(DOVSTA);
349235783Skib	if (tmp & (1 << 17))
350235783Skib		DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
351235783Skib
352235783Skib	ret = BEGIN_LP_RING(2);
353235783Skib	if (ret) {
354235783Skib		free(request, DRM_I915_GEM);
355235783Skib		return ret;
356235783Skib	}
357235783Skib	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
358235783Skib	OUT_RING(flip_addr);
359235783Skib	ADVANCE_LP_RING();
360235783Skib
361235783Skib	ret = i915_add_request(LP_RING(dev_priv), NULL, request);
362235783Skib	if (ret) {
363235783Skib		free(request, DRM_I915_GEM);
364235783Skib		return ret;
365235783Skib	}
366235783Skib
367235783Skib	overlay->last_flip_req = request->seqno;
368235783Skib	return 0;
369235783Skib}
370235783Skib
371235783Skibstatic void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
372235783Skib{
373235783Skib	struct drm_i915_gem_object *obj = overlay->old_vid_bo;
374235783Skib
375235783Skib	i915_gem_object_unpin(obj);
376235783Skib	drm_gem_object_unreference(&obj->base);
377235783Skib
378235783Skib	overlay->old_vid_bo = NULL;
379235783Skib}
380235783Skib
381235783Skibstatic void intel_overlay_off_tail(struct intel_overlay *overlay)
382235783Skib{
383235783Skib	struct drm_i915_gem_object *obj = overlay->vid_bo;
384235783Skib
385235783Skib	/* never have the overlay hw on without showing a frame */
386235783Skib	KASSERT(overlay->vid_bo != NULL, ("No vid_bo"));
387235783Skib
388235783Skib	i915_gem_object_unpin(obj);
389235783Skib	drm_gem_object_unreference(&obj->base);
390235783Skib	overlay->vid_bo = NULL;
391235783Skib
392235783Skib	overlay->crtc->overlay = NULL;
393235783Skib	overlay->crtc = NULL;
394235783Skib	overlay->active = 0;
395235783Skib}
396235783Skib
397235783Skib/* overlay needs to be disabled in OCMD reg */
398235783Skibstatic int intel_overlay_off(struct intel_overlay *overlay)
399235783Skib{
400235783Skib	struct drm_device *dev = overlay->dev;
401235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
402235783Skib	u32 flip_addr = overlay->flip_addr;
403235783Skib	struct drm_i915_gem_request *request;
404235783Skib	int ret;
405235783Skib
406235783Skib	KASSERT(overlay->active, ("Overlay is not active"));
407235783Skib
408235783Skib	request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
409235783Skib
410235783Skib	/* According to intel docs the overlay hw may hang (when switching
411235783Skib	 * off) without loading the filter coeffs. It is however unclear whether
412235783Skib	 * this applies to the disabling of the overlay or to the switching off
413235783Skib	 * of the hw. Do it in both cases */
414235783Skib	flip_addr |= OFC_UPDATE;
415235783Skib
416235783Skib	ret = BEGIN_LP_RING(6);
417235783Skib	if (ret) {
418235783Skib		free(request, DRM_I915_GEM);
419235783Skib		return ret;
420235783Skib	}
421235783Skib	/* wait for overlay to go idle */
422235783Skib	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
423235783Skib	OUT_RING(flip_addr);
424235783Skib	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
425235783Skib	/* turn overlay off */
426235783Skib	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
427235783Skib	OUT_RING(flip_addr);
428235783Skib	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
429235783Skib	ADVANCE_LP_RING();
430235783Skib
431235783Skib	return intel_overlay_do_wait_request(overlay, request,
432235783Skib					     intel_overlay_off_tail);
433235783Skib}
434235783Skib
435235783Skib/* recover from an interruption due to a signal
436235783Skib * We have to be careful not to repeat work forever an make forward progess. */
437235783Skibstatic int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
438235783Skib{
439235783Skib	struct drm_device *dev = overlay->dev;
440235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
441235783Skib	int ret;
442235783Skib
443235783Skib	if (overlay->last_flip_req == 0)
444235783Skib		return 0;
445235783Skib
446235783Skib	ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
447235783Skib				true);
448235783Skib	if (ret)
449235783Skib		return ret;
450235783Skib
451235783Skib	if (overlay->flip_tail)
452235783Skib		overlay->flip_tail(overlay);
453235783Skib
454235783Skib	overlay->last_flip_req = 0;
455235783Skib	return 0;
456235783Skib}
457235783Skib
458235783Skib/* Wait for pending overlay flip and release old frame.
459235783Skib * Needs to be called before the overlay register are changed
460235783Skib * via intel_overlay_(un)map_regs
461235783Skib */
462235783Skibstatic int intel_overlay_release_old_vid(struct intel_overlay *overlay)
463235783Skib{
464235783Skib	struct drm_device *dev = overlay->dev;
465235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
466235783Skib	int ret;
467235783Skib
468235783Skib	/* Only wait if there is actually an old frame to release to
469235783Skib	 * guarantee forward progress.
470235783Skib	 */
471235783Skib	if (!overlay->old_vid_bo)
472235783Skib		return 0;
473235783Skib
474235783Skib	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
475235783Skib		struct drm_i915_gem_request *request;
476235783Skib
477235783Skib		/* synchronous slowpath */
478235783Skib		request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
479235783Skib
480235783Skib		ret = BEGIN_LP_RING(2);
481235783Skib		if (ret) {
482235783Skib			free(request, DRM_I915_GEM);
483235783Skib			return ret;
484235783Skib		}
485235783Skib
486235783Skib		OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
487235783Skib		OUT_RING(MI_NOOP);
488235783Skib		ADVANCE_LP_RING();
489235783Skib
490235783Skib		ret = intel_overlay_do_wait_request(overlay, request,
491235783Skib						    intel_overlay_release_old_vid_tail);
492235783Skib		if (ret)
493235783Skib			return ret;
494235783Skib	}
495235783Skib
496235783Skib	intel_overlay_release_old_vid_tail(overlay);
497235783Skib	return 0;
498235783Skib}
499235783Skib
500235783Skibstruct put_image_params {
501235783Skib	int format;
502235783Skib	short dst_x;
503235783Skib	short dst_y;
504235783Skib	short dst_w;
505235783Skib	short dst_h;
506235783Skib	short src_w;
507235783Skib	short src_scan_h;
508235783Skib	short src_scan_w;
509235783Skib	short src_h;
510235783Skib	short stride_Y;
511235783Skib	short stride_UV;
512235783Skib	int offset_Y;
513235783Skib	int offset_U;
514235783Skib	int offset_V;
515235783Skib};
516235783Skib
517235783Skibstatic int packed_depth_bytes(u32 format)
518235783Skib{
519235783Skib	switch (format & I915_OVERLAY_DEPTH_MASK) {
520235783Skib	case I915_OVERLAY_YUV422:
521235783Skib		return 4;
522235783Skib	case I915_OVERLAY_YUV411:
523235783Skib		/* return 6; not implemented */
524235783Skib	default:
525235783Skib		return -EINVAL;
526235783Skib	}
527235783Skib}
528235783Skib
529235783Skibstatic int packed_width_bytes(u32 format, short width)
530235783Skib{
531235783Skib	switch (format & I915_OVERLAY_DEPTH_MASK) {
532235783Skib	case I915_OVERLAY_YUV422:
533235783Skib		return width << 1;
534235783Skib	default:
535235783Skib		return -EINVAL;
536235783Skib	}
537235783Skib}
538235783Skib
539235783Skibstatic int uv_hsubsampling(u32 format)
540235783Skib{
541235783Skib	switch (format & I915_OVERLAY_DEPTH_MASK) {
542235783Skib	case I915_OVERLAY_YUV422:
543235783Skib	case I915_OVERLAY_YUV420:
544235783Skib		return 2;
545235783Skib	case I915_OVERLAY_YUV411:
546235783Skib	case I915_OVERLAY_YUV410:
547235783Skib		return 4;
548235783Skib	default:
549235783Skib		return -EINVAL;
550235783Skib	}
551235783Skib}
552235783Skib
553235783Skibstatic int uv_vsubsampling(u32 format)
554235783Skib{
555235783Skib	switch (format & I915_OVERLAY_DEPTH_MASK) {
556235783Skib	case I915_OVERLAY_YUV420:
557235783Skib	case I915_OVERLAY_YUV410:
558235783Skib		return 2;
559235783Skib	case I915_OVERLAY_YUV422:
560235783Skib	case I915_OVERLAY_YUV411:
561235783Skib		return 1;
562235783Skib	default:
563235783Skib		return -EINVAL;
564235783Skib	}
565235783Skib}
566235783Skib
567235783Skibstatic u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
568235783Skib{
569235783Skib	u32 mask, shift, ret;
570235783Skib	if (IS_GEN2(dev)) {
571235783Skib		mask = 0x1f;
572235783Skib		shift = 5;
573235783Skib	} else {
574235783Skib		mask = 0x3f;
575235783Skib		shift = 6;
576235783Skib	}
577235783Skib	ret = ((offset + width + mask) >> shift) - (offset >> shift);
578235783Skib	if (!IS_GEN2(dev))
579235783Skib		ret <<= 1;
580235783Skib	ret -= 1;
581235783Skib	return ret << 2;
582235783Skib}
583235783Skib
584235783Skibstatic const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
585235783Skib	0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
586235783Skib	0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
587235783Skib	0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
588235783Skib	0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
589235783Skib	0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
590235783Skib	0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
591235783Skib	0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
592235783Skib	0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
593235783Skib	0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
594235783Skib	0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
595235783Skib	0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
596235783Skib	0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
597235783Skib	0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
598235783Skib	0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
599235783Skib	0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
600235783Skib	0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
601235783Skib	0xb000, 0x3000, 0x0800, 0x3000, 0xb000
602235783Skib};
603235783Skib
604235783Skibstatic const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
605235783Skib	0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
606235783Skib	0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
607235783Skib	0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
608235783Skib	0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
609235783Skib	0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
610235783Skib	0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
611235783Skib	0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
612235783Skib	0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
613235783Skib	0x3000, 0x0800, 0x3000
614235783Skib};
615235783Skib
616235783Skibstatic void update_polyphase_filter(struct overlay_registers *regs)
617235783Skib{
618235783Skib	memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
619235783Skib	memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
620235783Skib}
621235783Skib
622235783Skibstatic bool update_scaling_factors(struct intel_overlay *overlay,
623235783Skib				   struct overlay_registers *regs,
624235783Skib				   struct put_image_params *params)
625235783Skib{
626235783Skib	/* fixed point with a 12 bit shift */
627235783Skib	u32 xscale, yscale, xscale_UV, yscale_UV;
628235783Skib#define FP_SHIFT 12
629235783Skib#define FRACT_MASK 0xfff
630235783Skib	bool scale_changed = false;
631235783Skib	int uv_hscale = uv_hsubsampling(params->format);
632235783Skib	int uv_vscale = uv_vsubsampling(params->format);
633235783Skib
634235783Skib	if (params->dst_w > 1)
635235783Skib		xscale = ((params->src_scan_w - 1) << FP_SHIFT)
636235783Skib			/(params->dst_w);
637235783Skib	else
638235783Skib		xscale = 1 << FP_SHIFT;
639235783Skib
640235783Skib	if (params->dst_h > 1)
641235783Skib		yscale = ((params->src_scan_h - 1) << FP_SHIFT)
642235783Skib			/(params->dst_h);
643235783Skib	else
644235783Skib		yscale = 1 << FP_SHIFT;
645235783Skib
646235783Skib	/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
647235783Skib	xscale_UV = xscale/uv_hscale;
648235783Skib	yscale_UV = yscale/uv_vscale;
649235783Skib	/* make the Y scale to UV scale ratio an exact multiply */
650235783Skib	xscale = xscale_UV * uv_hscale;
651235783Skib	yscale = yscale_UV * uv_vscale;
652235783Skib	/*} else {
653235783Skib	  xscale_UV = 0;
654235783Skib	  yscale_UV = 0;
655235783Skib	  }*/
656235783Skib
657235783Skib	if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
658235783Skib		scale_changed = true;
659235783Skib	overlay->old_xscale = xscale;
660235783Skib	overlay->old_yscale = yscale;
661235783Skib
662235783Skib	regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
663235783Skib			   ((xscale >> FP_SHIFT)  << 16) |
664235783Skib			   ((xscale & FRACT_MASK) << 3));
665235783Skib
666235783Skib	regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
667235783Skib			 ((xscale_UV >> FP_SHIFT)  << 16) |
668235783Skib			 ((xscale_UV & FRACT_MASK) << 3));
669235783Skib
670235783Skib	regs->UVSCALEV = ((((yscale    >> FP_SHIFT) << 16) |
671235783Skib			   ((yscale_UV >> FP_SHIFT) << 0)));
672235783Skib
673235783Skib	if (scale_changed)
674235783Skib		update_polyphase_filter(regs);
675235783Skib
676235783Skib	return scale_changed;
677235783Skib}
678235783Skib
679235783Skibstatic void update_colorkey(struct intel_overlay *overlay,
680235783Skib			    struct overlay_registers *regs)
681235783Skib{
682235783Skib	u32 key = overlay->color_key;
683235783Skib
684235783Skib	switch (overlay->crtc->base.fb->bits_per_pixel) {
685235783Skib	case 8:
686235783Skib		regs->DCLRKV = 0;
687235783Skib		regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
688235783Skib		break;
689235783Skib
690235783Skib	case 16:
691235783Skib		if (overlay->crtc->base.fb->depth == 15) {
692235783Skib			regs->DCLRKV = RGB15_TO_COLORKEY(key);
693235783Skib			regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
694235783Skib		} else {
695235783Skib			regs->DCLRKV = RGB16_TO_COLORKEY(key);
696235783Skib			regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
697235783Skib		}
698235783Skib		break;
699235783Skib
700235783Skib	case 24:
701235783Skib	case 32:
702235783Skib		regs->DCLRKV = key;
703235783Skib		regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
704235783Skib		break;
705235783Skib	}
706235783Skib}
707235783Skib
708235783Skibstatic u32 overlay_cmd_reg(struct put_image_params *params)
709235783Skib{
710235783Skib	u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
711235783Skib
712235783Skib	if (params->format & I915_OVERLAY_YUV_PLANAR) {
713235783Skib		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
714235783Skib		case I915_OVERLAY_YUV422:
715235783Skib			cmd |= OCMD_YUV_422_PLANAR;
716235783Skib			break;
717235783Skib		case I915_OVERLAY_YUV420:
718235783Skib			cmd |= OCMD_YUV_420_PLANAR;
719235783Skib			break;
720235783Skib		case I915_OVERLAY_YUV411:
721235783Skib		case I915_OVERLAY_YUV410:
722235783Skib			cmd |= OCMD_YUV_410_PLANAR;
723235783Skib			break;
724235783Skib		}
725235783Skib	} else { /* YUV packed */
726235783Skib		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
727235783Skib		case I915_OVERLAY_YUV422:
728235783Skib			cmd |= OCMD_YUV_422_PACKED;
729235783Skib			break;
730235783Skib		case I915_OVERLAY_YUV411:
731235783Skib			cmd |= OCMD_YUV_411_PACKED;
732235783Skib			break;
733235783Skib		}
734235783Skib
735235783Skib		switch (params->format & I915_OVERLAY_SWAP_MASK) {
736235783Skib		case I915_OVERLAY_NO_SWAP:
737235783Skib			break;
738235783Skib		case I915_OVERLAY_UV_SWAP:
739235783Skib			cmd |= OCMD_UV_SWAP;
740235783Skib			break;
741235783Skib		case I915_OVERLAY_Y_SWAP:
742235783Skib			cmd |= OCMD_Y_SWAP;
743235783Skib			break;
744235783Skib		case I915_OVERLAY_Y_AND_UV_SWAP:
745235783Skib			cmd |= OCMD_Y_AND_UV_SWAP;
746235783Skib			break;
747235783Skib		}
748235783Skib	}
749235783Skib
750235783Skib	return cmd;
751235783Skib}
752235783Skib
753235783Skibstatic u32
754235783Skibmax_u32(u32 a, u32 b)
755235783Skib{
756235783Skib
757235783Skib	return (a > b ? a : b);
758235783Skib}
759235783Skib
760235783Skibstatic int intel_overlay_do_put_image(struct intel_overlay *overlay,
761235783Skib				      struct drm_i915_gem_object *new_bo,
762235783Skib				      struct put_image_params *params)
763235783Skib{
764235783Skib	int ret, tmp_width;
765235783Skib	struct overlay_registers *regs;
766235783Skib	bool scale_changed = false;
767235783Skib
768235783Skib	KASSERT(overlay != NULL, ("No overlay ?"));
769235783Skib	DRM_LOCK_ASSERT(overlay->dev);
770235783Skib	DRM_MODE_CONFIG_ASSERT_LOCKED(overlay->dev);
771235783Skib
772235783Skib	ret = intel_overlay_release_old_vid(overlay);
773235783Skib	if (ret != 0)
774235783Skib		return ret;
775235783Skib
776235783Skib	ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
777235783Skib	if (ret != 0)
778235783Skib		goto out_unpin;
779235783Skib
780235783Skib	ret = i915_gem_object_put_fence(new_bo);
781235783Skib	if (ret)
782235783Skib		goto out_unpin;
783235783Skib
784235783Skib	if (!overlay->active) {
785235783Skib		regs = intel_overlay_map_regs(overlay);
786235783Skib		if (!regs) {
787235783Skib			ret = -ENOMEM;
788235783Skib			goto out_unpin;
789235783Skib		}
790235783Skib		regs->OCONFIG = OCONF_CC_OUT_8BIT;
791235783Skib		if (IS_GEN4(overlay->dev))
792235783Skib			regs->OCONFIG |= OCONF_CSC_MODE_BT709;
793235783Skib		regs->OCONFIG |= overlay->crtc->pipe == 0 ?
794235783Skib			OCONF_PIPE_A : OCONF_PIPE_B;
795235783Skib		intel_overlay_unmap_regs(overlay, regs);
796235783Skib
797235783Skib		ret = intel_overlay_on(overlay);
798235783Skib		if (ret != 0)
799235783Skib			goto out_unpin;
800235783Skib	}
801235783Skib
802235783Skib	regs = intel_overlay_map_regs(overlay);
803235783Skib	if (!regs) {
804235783Skib		ret = -ENOMEM;
805235783Skib		goto out_unpin;
806235783Skib	}
807235783Skib
808235783Skib	regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
809235783Skib	regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
810235783Skib
811235783Skib	if (params->format & I915_OVERLAY_YUV_PACKED)
812235783Skib		tmp_width = packed_width_bytes(params->format, params->src_w);
813235783Skib	else
814235783Skib		tmp_width = params->src_w;
815235783Skib
816235783Skib	regs->SWIDTH = params->src_w;
817235783Skib	regs->SWIDTHSW = calc_swidthsw(overlay->dev,
818235783Skib				       params->offset_Y, tmp_width);
819235783Skib	regs->SHEIGHT = params->src_h;
820235783Skib	regs->OBUF_0Y = new_bo->gtt_offset + params->offset_Y;
821235783Skib	regs->OSTRIDE = params->stride_Y;
822235783Skib
823235783Skib	if (params->format & I915_OVERLAY_YUV_PLANAR) {
824235783Skib		int uv_hscale = uv_hsubsampling(params->format);
825235783Skib		int uv_vscale = uv_vsubsampling(params->format);
826235783Skib		u32 tmp_U, tmp_V;
827235783Skib		regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
828235783Skib		tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
829235783Skib				      params->src_w/uv_hscale);
830235783Skib		tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
831235783Skib				      params->src_w/uv_hscale);
832235783Skib		regs->SWIDTHSW |= max_u32(tmp_U, tmp_V) << 16;
833235783Skib		regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
834235783Skib		regs->OBUF_0U = new_bo->gtt_offset + params->offset_U;
835235783Skib		regs->OBUF_0V = new_bo->gtt_offset + params->offset_V;
836235783Skib		regs->OSTRIDE |= params->stride_UV << 16;
837235783Skib	}
838235783Skib
839235783Skib	scale_changed = update_scaling_factors(overlay, regs, params);
840235783Skib
841235783Skib	update_colorkey(overlay, regs);
842235783Skib
843235783Skib	regs->OCMD = overlay_cmd_reg(params);
844235783Skib
845235783Skib	intel_overlay_unmap_regs(overlay, regs);
846235783Skib
847235783Skib	ret = intel_overlay_continue(overlay, scale_changed);
848235783Skib	if (ret)
849235783Skib		goto out_unpin;
850235783Skib
851235783Skib	overlay->old_vid_bo = overlay->vid_bo;
852235783Skib	overlay->vid_bo = new_bo;
853235783Skib
854235783Skib	return 0;
855235783Skib
856235783Skibout_unpin:
857235783Skib	i915_gem_object_unpin(new_bo);
858235783Skib	return ret;
859235783Skib}
860235783Skib
861235783Skibint intel_overlay_switch_off(struct intel_overlay *overlay)
862235783Skib{
863235783Skib	struct overlay_registers *regs;
864235783Skib	int ret;
865235783Skib
866235783Skib	DRM_LOCK_ASSERT(overlay->dev);
867235783Skib	DRM_MODE_CONFIG_ASSERT_LOCKED(overlay->dev);
868235783Skib
869235783Skib	ret = intel_overlay_recover_from_interrupt(overlay);
870235783Skib	if (ret != 0)
871235783Skib		return ret;
872235783Skib
873235783Skib	if (!overlay->active)
874235783Skib		return 0;
875235783Skib
876235783Skib	ret = intel_overlay_release_old_vid(overlay);
877235783Skib	if (ret != 0)
878235783Skib		return ret;
879235783Skib
880235783Skib	regs = intel_overlay_map_regs(overlay);
881235783Skib	regs->OCMD = 0;
882235783Skib	intel_overlay_unmap_regs(overlay, regs);
883235783Skib
884235783Skib	ret = intel_overlay_off(overlay);
885235783Skib	if (ret != 0)
886235783Skib		return ret;
887235783Skib
888235783Skib	intel_overlay_off_tail(overlay);
889235783Skib	return 0;
890235783Skib}
891235783Skib
892235783Skibstatic int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
893235783Skib					  struct intel_crtc *crtc)
894235783Skib{
895235783Skib	drm_i915_private_t *dev_priv = overlay->dev->dev_private;
896235783Skib
897235783Skib	if (!crtc->active)
898235783Skib		return -EINVAL;
899235783Skib
900235783Skib	/* can't use the overlay with double wide pipe */
901235783Skib	if (INTEL_INFO(overlay->dev)->gen < 4 &&
902235783Skib	    (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
903235783Skib		return -EINVAL;
904235783Skib
905235783Skib	return 0;
906235783Skib}
907235783Skib
908235783Skibstatic void update_pfit_vscale_ratio(struct intel_overlay *overlay)
909235783Skib{
910235783Skib	struct drm_device *dev = overlay->dev;
911235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
912235783Skib	u32 pfit_control = I915_READ(PFIT_CONTROL);
913235783Skib	u32 ratio;
914235783Skib
915235783Skib	/* XXX: This is not the same logic as in the xorg driver, but more in
916235783Skib	 * line with the intel documentation for the i965
917235783Skib	 */
918235783Skib	if (INTEL_INFO(dev)->gen >= 4) {
919235783Skib		/* on i965 use the PGM reg to read out the autoscaler values */
920235783Skib		ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
921235783Skib	} else {
922235783Skib		if (pfit_control & VERT_AUTO_SCALE)
923235783Skib			ratio = I915_READ(PFIT_AUTO_RATIOS);
924235783Skib		else
925235783Skib			ratio = I915_READ(PFIT_PGM_RATIOS);
926235783Skib		ratio >>= PFIT_VERT_SCALE_SHIFT;
927235783Skib	}
928235783Skib
929235783Skib	overlay->pfit_vscale_ratio = ratio;
930235783Skib}
931235783Skib
932235783Skibstatic int check_overlay_dst(struct intel_overlay *overlay,
933235783Skib			     struct drm_intel_overlay_put_image *rec)
934235783Skib{
935235783Skib	struct drm_display_mode *mode = &overlay->crtc->base.mode;
936235783Skib
937235783Skib	if (rec->dst_x < mode->hdisplay &&
938235783Skib	    rec->dst_x + rec->dst_width <= mode->hdisplay &&
939235783Skib	    rec->dst_y < mode->vdisplay &&
940235783Skib	    rec->dst_y + rec->dst_height <= mode->vdisplay)
941235783Skib		return 0;
942235783Skib	else
943235783Skib		return -EINVAL;
944235783Skib}
945235783Skib
946235783Skibstatic int check_overlay_scaling(struct put_image_params *rec)
947235783Skib{
948235783Skib	u32 tmp;
949235783Skib
950235783Skib	/* downscaling limit is 8.0 */
951235783Skib	tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
952235783Skib	if (tmp > 7)
953235783Skib		return -EINVAL;
954235783Skib	tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
955235783Skib	if (tmp > 7)
956235783Skib		return -EINVAL;
957235783Skib
958235783Skib	return 0;
959235783Skib}
960235783Skib
961235783Skibstatic int check_overlay_src(struct drm_device *dev,
962235783Skib			     struct drm_intel_overlay_put_image *rec,
963235783Skib			     struct drm_i915_gem_object *new_bo)
964235783Skib{
965235783Skib	int uv_hscale = uv_hsubsampling(rec->flags);
966235783Skib	int uv_vscale = uv_vsubsampling(rec->flags);
967235783Skib	u32 stride_mask;
968235783Skib	int depth;
969235783Skib	u32 tmp;
970235783Skib
971235783Skib	/* check src dimensions */
972235783Skib	if (IS_845G(dev) || IS_I830(dev)) {
973235783Skib		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
974235783Skib		    rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
975235783Skib			return -EINVAL;
976235783Skib	} else {
977235783Skib		if (rec->src_height > IMAGE_MAX_HEIGHT ||
978235783Skib		    rec->src_width  > IMAGE_MAX_WIDTH)
979235783Skib			return -EINVAL;
980235783Skib	}
981235783Skib
982235783Skib	/* better safe than sorry, use 4 as the maximal subsampling ratio */
983235783Skib	if (rec->src_height < N_VERT_Y_TAPS*4 ||
984235783Skib	    rec->src_width  < N_HORIZ_Y_TAPS*4)
985235783Skib		return -EINVAL;
986235783Skib
987235783Skib	/* check alignment constraints */
988235783Skib	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
989235783Skib	case I915_OVERLAY_RGB:
990235783Skib		/* not implemented */
991235783Skib		return -EINVAL;
992235783Skib
993235783Skib	case I915_OVERLAY_YUV_PACKED:
994235783Skib		if (uv_vscale != 1)
995235783Skib			return -EINVAL;
996235783Skib
997235783Skib		depth = packed_depth_bytes(rec->flags);
998235783Skib		if (depth < 0)
999235783Skib			return depth;
1000235783Skib
1001235783Skib		/* ignore UV planes */
1002235783Skib		rec->stride_UV = 0;
1003235783Skib		rec->offset_U = 0;
1004235783Skib		rec->offset_V = 0;
1005235783Skib		/* check pixel alignment */
1006235783Skib		if (rec->offset_Y % depth)
1007235783Skib			return -EINVAL;
1008235783Skib		break;
1009235783Skib
1010235783Skib	case I915_OVERLAY_YUV_PLANAR:
1011235783Skib		if (uv_vscale < 0 || uv_hscale < 0)
1012235783Skib			return -EINVAL;
1013235783Skib		/* no offset restrictions for planar formats */
1014235783Skib		break;
1015235783Skib
1016235783Skib	default:
1017235783Skib		return -EINVAL;
1018235783Skib	}
1019235783Skib
1020235783Skib	if (rec->src_width % uv_hscale)
1021235783Skib		return -EINVAL;
1022235783Skib
1023235783Skib	/* stride checking */
1024235783Skib	if (IS_I830(dev) || IS_845G(dev))
1025235783Skib		stride_mask = 255;
1026235783Skib	else
1027235783Skib		stride_mask = 63;
1028235783Skib
1029235783Skib	if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1030235783Skib		return -EINVAL;
1031235783Skib	if (IS_GEN4(dev) && rec->stride_Y < 512)
1032235783Skib		return -EINVAL;
1033235783Skib
1034235783Skib	tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
1035235783Skib		4096 : 8192;
1036235783Skib	if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
1037235783Skib		return -EINVAL;
1038235783Skib
1039235783Skib	/* check buffer dimensions */
1040235783Skib	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
1041235783Skib	case I915_OVERLAY_RGB:
1042235783Skib	case I915_OVERLAY_YUV_PACKED:
1043235783Skib		/* always 4 Y values per depth pixels */
1044235783Skib		if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1045235783Skib			return -EINVAL;
1046235783Skib
1047235783Skib		tmp = rec->stride_Y*rec->src_height;
1048235783Skib		if (rec->offset_Y + tmp > new_bo->base.size)
1049235783Skib			return -EINVAL;
1050235783Skib		break;
1051235783Skib
1052235783Skib	case I915_OVERLAY_YUV_PLANAR:
1053235783Skib		if (rec->src_width > rec->stride_Y)
1054235783Skib			return -EINVAL;
1055235783Skib		if (rec->src_width/uv_hscale > rec->stride_UV)
1056235783Skib			return -EINVAL;
1057235783Skib
1058235783Skib		tmp = rec->stride_Y * rec->src_height;
1059235783Skib		if (rec->offset_Y + tmp > new_bo->base.size)
1060235783Skib			return -EINVAL;
1061235783Skib
1062235783Skib		tmp = rec->stride_UV * (rec->src_height / uv_vscale);
1063235783Skib		if (rec->offset_U + tmp > new_bo->base.size ||
1064235783Skib		    rec->offset_V + tmp > new_bo->base.size)
1065235783Skib			return -EINVAL;
1066235783Skib		break;
1067235783Skib	}
1068235783Skib
1069235783Skib	return 0;
1070235783Skib}
1071235783Skib
1072235783Skib/**
1073235783Skib * Return the pipe currently connected to the panel fitter,
1074235783Skib * or -1 if the panel fitter is not present or not in use
1075235783Skib */
1076235783Skibstatic int intel_panel_fitter_pipe(struct drm_device *dev)
1077235783Skib{
1078235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
1079235783Skib	u32  pfit_control;
1080235783Skib
1081235783Skib	/* i830 doesn't have a panel fitter */
1082235783Skib	if (IS_I830(dev))
1083235783Skib		return -1;
1084235783Skib
1085235783Skib	pfit_control = I915_READ(PFIT_CONTROL);
1086235783Skib
1087235783Skib	/* See if the panel fitter is in use */
1088235783Skib	if ((pfit_control & PFIT_ENABLE) == 0)
1089235783Skib		return -1;
1090235783Skib
1091235783Skib	/* 965 can place panel fitter on either pipe */
1092235783Skib	if (IS_GEN4(dev))
1093235783Skib		return (pfit_control >> 29) & 0x3;
1094235783Skib
1095235783Skib	/* older chips can only use pipe 1 */
1096235783Skib	return 1;
1097235783Skib}
1098235783Skib
1099235783Skibint intel_overlay_put_image(struct drm_device *dev, void *data,
1100235783Skib			    struct drm_file *file_priv)
1101235783Skib{
1102235783Skib	struct drm_intel_overlay_put_image *put_image_rec = data;
1103235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
1104235783Skib	struct intel_overlay *overlay;
1105235783Skib	struct drm_mode_object *drmmode_obj;
1106235783Skib	struct intel_crtc *crtc;
1107235783Skib	struct drm_i915_gem_object *new_bo;
1108235783Skib	struct put_image_params *params;
1109235783Skib	int ret;
1110235783Skib
1111235783Skib	if (!dev_priv) {
1112235783Skib		DRM_ERROR("called with no initialization\n");
1113235783Skib		return -EINVAL;
1114235783Skib	}
1115235783Skib
1116235783Skib	overlay = dev_priv->overlay;
1117235783Skib	if (!overlay) {
1118235783Skib		DRM_DEBUG("userspace bug: no overlay\n");
1119235783Skib		return -ENODEV;
1120235783Skib	}
1121235783Skib
1122235783Skib	if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1123235783Skib		sx_xlock(&dev->mode_config.mutex);
1124235783Skib		DRM_LOCK(dev);
1125235783Skib
1126235783Skib		ret = intel_overlay_switch_off(overlay);
1127235783Skib
1128235783Skib		DRM_UNLOCK(dev);
1129235783Skib		sx_xunlock(&dev->mode_config.mutex);
1130235783Skib
1131235783Skib		return ret;
1132235783Skib	}
1133235783Skib
1134235783Skib	params = malloc(sizeof(struct put_image_params), DRM_I915_GEM,
1135235783Skib	    M_WAITOK | M_ZERO);
1136235783Skib
1137235783Skib	drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
1138235783Skib					   DRM_MODE_OBJECT_CRTC);
1139235783Skib	if (!drmmode_obj) {
1140235783Skib		ret = -ENOENT;
1141235783Skib		goto out_free;
1142235783Skib	}
1143235783Skib	crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
1144235783Skib
1145235783Skib	new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv,
1146235783Skib						   put_image_rec->bo_handle));
1147235783Skib	if (&new_bo->base == NULL) {
1148235783Skib		ret = -ENOENT;
1149235783Skib		goto out_free;
1150235783Skib	}
1151235783Skib
1152235783Skib	sx_xlock(&dev->mode_config.mutex);
1153235783Skib	DRM_LOCK(dev);
1154235783Skib
1155235783Skib	if (new_bo->tiling_mode) {
1156235783Skib		DRM_ERROR("buffer used for overlay image can not be tiled\n");
1157235783Skib		ret = -EINVAL;
1158235783Skib		goto out_unlock;
1159235783Skib	}
1160235783Skib
1161235783Skib	ret = intel_overlay_recover_from_interrupt(overlay);
1162235783Skib	if (ret != 0)
1163235783Skib		goto out_unlock;
1164235783Skib
1165235783Skib	if (overlay->crtc != crtc) {
1166235783Skib		struct drm_display_mode *mode = &crtc->base.mode;
1167235783Skib		ret = intel_overlay_switch_off(overlay);
1168235783Skib		if (ret != 0)
1169235783Skib			goto out_unlock;
1170235783Skib
1171235783Skib		ret = check_overlay_possible_on_crtc(overlay, crtc);
1172235783Skib		if (ret != 0)
1173235783Skib			goto out_unlock;
1174235783Skib
1175235783Skib		overlay->crtc = crtc;
1176235783Skib		crtc->overlay = overlay;
1177235783Skib
1178235783Skib		/* line too wide, i.e. one-line-mode */
1179235783Skib		if (mode->hdisplay > 1024 &&
1180235783Skib		    intel_panel_fitter_pipe(dev) == crtc->pipe) {
1181235783Skib			overlay->pfit_active = 1;
1182235783Skib			update_pfit_vscale_ratio(overlay);
1183235783Skib		} else
1184235783Skib			overlay->pfit_active = 0;
1185235783Skib	}
1186235783Skib
1187235783Skib	ret = check_overlay_dst(overlay, put_image_rec);
1188235783Skib	if (ret != 0)
1189235783Skib		goto out_unlock;
1190235783Skib
1191235783Skib	if (overlay->pfit_active) {
1192235783Skib		params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1193235783Skib				 overlay->pfit_vscale_ratio);
1194235783Skib		/* shifting right rounds downwards, so add 1 */
1195235783Skib		params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1196235783Skib				 overlay->pfit_vscale_ratio) + 1;
1197235783Skib	} else {
1198235783Skib		params->dst_y = put_image_rec->dst_y;
1199235783Skib		params->dst_h = put_image_rec->dst_height;
1200235783Skib	}
1201235783Skib	params->dst_x = put_image_rec->dst_x;
1202235783Skib	params->dst_w = put_image_rec->dst_width;
1203235783Skib
1204235783Skib	params->src_w = put_image_rec->src_width;
1205235783Skib	params->src_h = put_image_rec->src_height;
1206235783Skib	params->src_scan_w = put_image_rec->src_scan_width;
1207235783Skib	params->src_scan_h = put_image_rec->src_scan_height;
1208235783Skib	if (params->src_scan_h > params->src_h ||
1209235783Skib	    params->src_scan_w > params->src_w) {
1210235783Skib		ret = -EINVAL;
1211235783Skib		goto out_unlock;
1212235783Skib	}
1213235783Skib
1214235783Skib	ret = check_overlay_src(dev, put_image_rec, new_bo);
1215235783Skib	if (ret != 0)
1216235783Skib		goto out_unlock;
1217235783Skib	params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1218235783Skib	params->stride_Y = put_image_rec->stride_Y;
1219235783Skib	params->stride_UV = put_image_rec->stride_UV;
1220235783Skib	params->offset_Y = put_image_rec->offset_Y;
1221235783Skib	params->offset_U = put_image_rec->offset_U;
1222235783Skib	params->offset_V = put_image_rec->offset_V;
1223235783Skib
1224235783Skib	/* Check scaling after src size to prevent a divide-by-zero. */
1225235783Skib	ret = check_overlay_scaling(params);
1226235783Skib	if (ret != 0)
1227235783Skib		goto out_unlock;
1228235783Skib
1229235783Skib	ret = intel_overlay_do_put_image(overlay, new_bo, params);
1230235783Skib	if (ret != 0)
1231235783Skib		goto out_unlock;
1232235783Skib
1233235783Skib	DRM_UNLOCK(dev);
1234235783Skib	sx_xunlock(&dev->mode_config.mutex);
1235235783Skib
1236235783Skib	free(params, DRM_I915_GEM);
1237235783Skib
1238235783Skib	return 0;
1239235783Skib
1240235783Skibout_unlock:
1241235783Skib	DRM_UNLOCK(dev);
1242235783Skib	sx_xunlock(&dev->mode_config.mutex);
1243235783Skib	drm_gem_object_unreference_unlocked(&new_bo->base);
1244235783Skibout_free:
1245235783Skib	free(params, DRM_I915_GEM);
1246235783Skib
1247235783Skib	return ret;
1248235783Skib}
1249235783Skib
1250235783Skibstatic void update_reg_attrs(struct intel_overlay *overlay,
1251235783Skib			     struct overlay_registers *regs)
1252235783Skib{
1253235783Skib	regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1254235783Skib	regs->OCLRC1 = overlay->saturation;
1255235783Skib}
1256235783Skib
1257235783Skibstatic bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1258235783Skib{
1259235783Skib	int i;
1260235783Skib
1261235783Skib	if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1262235783Skib		return false;
1263235783Skib
1264235783Skib	for (i = 0; i < 3; i++) {
1265235783Skib		if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1266235783Skib			return false;
1267235783Skib	}
1268235783Skib
1269235783Skib	return true;
1270235783Skib}
1271235783Skib
1272235783Skibstatic bool check_gamma5_errata(u32 gamma5)
1273235783Skib{
1274235783Skib	int i;
1275235783Skib
1276235783Skib	for (i = 0; i < 3; i++) {
1277235783Skib		if (((gamma5 >> i*8) & 0xff) == 0x80)
1278235783Skib			return false;
1279235783Skib	}
1280235783Skib
1281235783Skib	return true;
1282235783Skib}
1283235783Skib
1284235783Skibstatic int check_gamma(struct drm_intel_overlay_attrs *attrs)
1285235783Skib{
1286235783Skib	if (!check_gamma_bounds(0, attrs->gamma0) ||
1287235783Skib	    !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1288235783Skib	    !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1289235783Skib	    !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1290235783Skib	    !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1291235783Skib	    !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1292235783Skib	    !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1293235783Skib		return -EINVAL;
1294235783Skib
1295235783Skib	if (!check_gamma5_errata(attrs->gamma5))
1296235783Skib		return -EINVAL;
1297235783Skib
1298235783Skib	return 0;
1299235783Skib}
1300235783Skib
1301235783Skibint intel_overlay_attrs(struct drm_device *dev, void *data,
1302235783Skib			struct drm_file *file_priv)
1303235783Skib{
1304235783Skib	struct drm_intel_overlay_attrs *attrs = data;
1305235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
1306235783Skib	struct intel_overlay *overlay;
1307235783Skib	struct overlay_registers *regs;
1308235783Skib	int ret;
1309235783Skib
1310235783Skib	if (!dev_priv) {
1311235783Skib		DRM_ERROR("called with no initialization\n");
1312235783Skib		return -EINVAL;
1313235783Skib	}
1314235783Skib
1315235783Skib	overlay = dev_priv->overlay;
1316235783Skib	if (!overlay) {
1317235783Skib		DRM_DEBUG("userspace bug: no overlay\n");
1318235783Skib		return -ENODEV;
1319235783Skib	}
1320235783Skib
1321235783Skib	sx_xlock(&dev->mode_config.mutex);
1322235783Skib	DRM_LOCK(dev);
1323235783Skib
1324235783Skib	ret = -EINVAL;
1325235783Skib	if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1326235783Skib		attrs->color_key  = overlay->color_key;
1327235783Skib		attrs->brightness = overlay->brightness;
1328235783Skib		attrs->contrast   = overlay->contrast;
1329235783Skib		attrs->saturation = overlay->saturation;
1330235783Skib
1331235783Skib		if (!IS_GEN2(dev)) {
1332235783Skib			attrs->gamma0 = I915_READ(OGAMC0);
1333235783Skib			attrs->gamma1 = I915_READ(OGAMC1);
1334235783Skib			attrs->gamma2 = I915_READ(OGAMC2);
1335235783Skib			attrs->gamma3 = I915_READ(OGAMC3);
1336235783Skib			attrs->gamma4 = I915_READ(OGAMC4);
1337235783Skib			attrs->gamma5 = I915_READ(OGAMC5);
1338235783Skib		}
1339235783Skib	} else {
1340235783Skib		if (attrs->brightness < -128 || attrs->brightness > 127)
1341235783Skib			goto out_unlock;
1342235783Skib		if (attrs->contrast > 255)
1343235783Skib			goto out_unlock;
1344235783Skib		if (attrs->saturation > 1023)
1345235783Skib			goto out_unlock;
1346235783Skib
1347235783Skib		overlay->color_key  = attrs->color_key;
1348235783Skib		overlay->brightness = attrs->brightness;
1349235783Skib		overlay->contrast   = attrs->contrast;
1350235783Skib		overlay->saturation = attrs->saturation;
1351235783Skib
1352235783Skib		regs = intel_overlay_map_regs(overlay);
1353235783Skib		if (!regs) {
1354235783Skib			ret = -ENOMEM;
1355235783Skib			goto out_unlock;
1356235783Skib		}
1357235783Skib
1358235783Skib		update_reg_attrs(overlay, regs);
1359235783Skib
1360235783Skib		intel_overlay_unmap_regs(overlay, regs);
1361235783Skib
1362235783Skib		if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1363235783Skib			if (IS_GEN2(dev))
1364235783Skib				goto out_unlock;
1365235783Skib
1366235783Skib			if (overlay->active) {
1367235783Skib				ret = -EBUSY;
1368235783Skib				goto out_unlock;
1369235783Skib			}
1370235783Skib
1371235783Skib			ret = check_gamma(attrs);
1372235783Skib			if (ret)
1373235783Skib				goto out_unlock;
1374235783Skib
1375235783Skib			I915_WRITE(OGAMC0, attrs->gamma0);
1376235783Skib			I915_WRITE(OGAMC1, attrs->gamma1);
1377235783Skib			I915_WRITE(OGAMC2, attrs->gamma2);
1378235783Skib			I915_WRITE(OGAMC3, attrs->gamma3);
1379235783Skib			I915_WRITE(OGAMC4, attrs->gamma4);
1380235783Skib			I915_WRITE(OGAMC5, attrs->gamma5);
1381235783Skib		}
1382235783Skib	}
1383235783Skib
1384235783Skib	ret = 0;
1385235783Skibout_unlock:
1386235783Skib	DRM_UNLOCK(dev);
1387235783Skib	sx_xunlock(&dev->mode_config.mutex);
1388235783Skib
1389235783Skib	return ret;
1390235783Skib}
1391235783Skib
1392235783Skibvoid intel_setup_overlay(struct drm_device *dev)
1393235783Skib{
1394235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
1395235783Skib	struct intel_overlay *overlay;
1396235783Skib	struct drm_i915_gem_object *reg_bo;
1397235783Skib	struct overlay_registers *regs;
1398235783Skib	int ret;
1399235783Skib
1400235783Skib	if (!HAS_OVERLAY(dev))
1401235783Skib		return;
1402235783Skib
1403235783Skib	overlay = malloc(sizeof(struct intel_overlay), DRM_I915_GEM,
1404235783Skib	    M_WAITOK | M_ZERO);
1405235783Skib	DRM_LOCK(dev);
1406235783Skib	if (dev_priv->overlay != NULL)
1407235783Skib		goto out_free;
1408235783Skib	overlay->dev = dev;
1409235783Skib
1410235783Skib	reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
1411235783Skib	if (!reg_bo)
1412235783Skib		goto out_free;
1413235783Skib	overlay->reg_bo = reg_bo;
1414235783Skib
1415235783Skib	if (OVERLAY_NEEDS_PHYSICAL(dev)) {
1416235783Skib		ret = i915_gem_attach_phys_object(dev, reg_bo,
1417235783Skib						  I915_GEM_PHYS_OVERLAY_REGS,
1418235783Skib						  PAGE_SIZE);
1419235783Skib		if (ret) {
1420235783Skib			DRM_ERROR("failed to attach phys overlay regs\n");
1421235783Skib			goto out_free_bo;
1422235783Skib		}
1423235783Skib		overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
1424235783Skib	} else {
1425235783Skib		ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
1426235783Skib		if (ret) {
1427235783Skib			DRM_ERROR("failed to pin overlay register bo\n");
1428235783Skib			goto out_free_bo;
1429235783Skib		}
1430235783Skib		overlay->flip_addr = reg_bo->gtt_offset;
1431235783Skib
1432235783Skib		ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1433235783Skib		if (ret) {
1434235783Skib			DRM_ERROR("failed to move overlay register bo into the GTT\n");
1435235783Skib			goto out_unpin_bo;
1436235783Skib		}
1437235783Skib	}
1438235783Skib
1439235783Skib	/* init all values */
1440235783Skib	overlay->color_key = 0x0101fe;
1441235783Skib	overlay->brightness = -19;
1442235783Skib	overlay->contrast = 75;
1443235783Skib	overlay->saturation = 146;
1444235783Skib
1445235783Skib	regs = intel_overlay_map_regs(overlay);
1446235783Skib	if (!regs)
1447235783Skib		goto out_unpin_bo;
1448235783Skib
1449235783Skib	memset(regs, 0, sizeof(struct overlay_registers));
1450235783Skib	update_polyphase_filter(regs);
1451235783Skib	update_reg_attrs(overlay, regs);
1452235783Skib
1453235783Skib	intel_overlay_unmap_regs(overlay, regs);
1454235783Skib
1455235783Skib	dev_priv->overlay = overlay;
1456235783Skib	DRM_INFO("initialized overlay support\n");
1457235783Skib	DRM_UNLOCK(dev);
1458235783Skib	return;
1459235783Skib
1460235783Skibout_unpin_bo:
1461235783Skib	if (!OVERLAY_NEEDS_PHYSICAL(dev))
1462235783Skib		i915_gem_object_unpin(reg_bo);
1463235783Skibout_free_bo:
1464235783Skib	drm_gem_object_unreference(&reg_bo->base);
1465235783Skibout_free:
1466235783Skib	DRM_UNLOCK(dev);
1467235783Skib	free(overlay, DRM_I915_GEM);
1468235783Skib	return;
1469235783Skib}
1470235783Skib
1471235783Skibvoid intel_cleanup_overlay(struct drm_device *dev)
1472235783Skib{
1473235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
1474235783Skib
1475235783Skib	if (!dev_priv->overlay)
1476235783Skib		return;
1477235783Skib
1478235783Skib	/* The bo's should be free'd by the generic code already.
1479235783Skib	 * Furthermore modesetting teardown happens beforehand so the
1480235783Skib	 * hardware should be off already */
1481235783Skib	KASSERT(!dev_priv->overlay->active, ("Overlay still active"));
1482235783Skib
1483235783Skib	drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
1484235783Skib	free(dev_priv->overlay, DRM_I915_GEM);
1485235783Skib}
1486235783Skib
1487235783Skibstruct intel_overlay_error_state {
1488235783Skib	struct overlay_registers regs;
1489235783Skib	unsigned long base;
1490235783Skib	u32 dovsta;
1491235783Skib	u32 isr;
1492235783Skib};
1493235783Skib
1494235783Skibstruct intel_overlay_error_state *
1495235783Skibintel_overlay_capture_error_state(struct drm_device *dev)
1496235783Skib{
1497235783Skib	drm_i915_private_t *dev_priv = dev->dev_private;
1498235783Skib	struct intel_overlay *overlay = dev_priv->overlay;
1499235783Skib	struct intel_overlay_error_state *error;
1500235783Skib	struct overlay_registers __iomem *regs;
1501235783Skib
1502235783Skib	if (!overlay || !overlay->active)
1503235783Skib		return NULL;
1504235783Skib
1505235783Skib	error = malloc(sizeof(*error), DRM_I915_GEM, M_NOWAIT);
1506235783Skib	if (error == NULL)
1507235783Skib		return NULL;
1508235783Skib
1509235783Skib	error->dovsta = I915_READ(DOVSTA);
1510235783Skib	error->isr = I915_READ(ISR);
1511235783Skib	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1512235783Skib		error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
1513235783Skib	else
1514235783Skib		error->base = (long) overlay->reg_bo->gtt_offset;
1515235783Skib
1516235783Skib	regs = intel_overlay_map_regs(overlay);
1517235783Skib	if (!regs)
1518235783Skib		goto err;
1519235783Skib
1520235783Skib	memcpy(&error->regs, regs, sizeof(struct overlay_registers));
1521235783Skib	intel_overlay_unmap_regs(overlay, regs);
1522235783Skib
1523235783Skib	return (error);
1524235783Skib
1525235783Skiberr:
1526235783Skib	free(error, DRM_I915_GEM);
1527235783Skib	return (NULL);
1528235783Skib}
1529235783Skib
1530235783Skibvoid
1531235783Skibintel_overlay_print_error_state(struct sbuf *m,
1532235783Skib    struct intel_overlay_error_state *error)
1533235783Skib{
1534235783Skib	sbuf_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1535235783Skib	    error->dovsta, error->isr);
1536235783Skib	sbuf_printf(m, "  Register file at 0x%08lx:\n",
1537235783Skib	    error->base);
1538235783Skib
1539235783Skib#define P(x) sbuf_printf(m, "    " #x ":	0x%08x\n", error->regs.x)
1540235783Skib	P(OBUF_0Y);
1541235783Skib	P(OBUF_1Y);
1542235783Skib	P(OBUF_0U);
1543235783Skib	P(OBUF_0V);
1544235783Skib	P(OBUF_1U);
1545235783Skib	P(OBUF_1V);
1546235783Skib	P(OSTRIDE);
1547235783Skib	P(YRGB_VPH);
1548235783Skib	P(UV_VPH);
1549235783Skib	P(HORZ_PH);
1550235783Skib	P(INIT_PHS);
1551235783Skib	P(DWINPOS);
1552235783Skib	P(DWINSZ);
1553235783Skib	P(SWIDTH);
1554235783Skib	P(SWIDTHSW);
1555235783Skib	P(SHEIGHT);
1556235783Skib	P(YRGBSCALE);
1557235783Skib	P(UVSCALE);
1558235783Skib	P(OCLRC0);
1559235783Skib	P(OCLRC1);
1560235783Skib	P(DCLRKV);
1561235783Skib	P(DCLRKM);
1562235783Skib	P(SCLRKVH);
1563235783Skib	P(SCLRKVL);
1564235783Skib	P(SCLRKEN);
1565235783Skib	P(OCONFIG);
1566235783Skib	P(OCMD);
1567235783Skib	P(OSTART_0Y);
1568235783Skib	P(OSTART_1Y);
1569235783Skib	P(OSTART_0U);
1570235783Skib	P(OSTART_0V);
1571235783Skib	P(OSTART_1U);
1572235783Skib	P(OSTART_1V);
1573235783Skib	P(OTILEOFF_0Y);
1574235783Skib	P(OTILEOFF_1Y);
1575235783Skib	P(OTILEOFF_0U);
1576235783Skib	P(OTILEOFF_0V);
1577235783Skib	P(OTILEOFF_1U);
1578235783Skib	P(OTILEOFF_1V);
1579235783Skib	P(FASTHSCALE);
1580235783Skib	P(UVSCALEV);
1581235783Skib#undef P
1582235783Skib}
1583