aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2009-09-15 16:57:34 -0400
committerEric Anholt <eric@anholt.net>2009-11-05 17:47:08 -0500
commit02e792fbaadb75dec8e476a05b610e49908fc6a4 (patch)
tree3c813fbf64431827b0e56291c647e60443a52277 /drivers
parentf0f8a9cecea322b215600d96cf0c1eb08343a4e9 (diff)
drm/i915: implement drmmode overlay support v4
This implements intel overlay support for kms via a device-specific ioctl. Thomas Hellstrom brought up the idea of a general ioctl (on dri-devel). We've reached the conclusion that such an infrastructure only makes sense when multiple kms overlay implementations exists, which atm don't (and it doesn't look like this is gonna change). Open issues: - Runs in sync with the gpu, i.e. unnecessary waiting. I've decided to wait on this because the hw tends to hang when changing something in this area. I left some dummy functions as infrastructure. - polyphase filtering uses a static table. - uses uninterruptible sleeps. Unfortunately the alternatives may unnecessarily wedged the hw if/when we timeout too early (and userspace only overloaded the batch buffers with stuff worth a few secs of gpu time). Changes since v1: - fix off-by-one misconception on my side. This fixes fullscreen playback. Changes since v2: - add underrun detection as spec'ed for i965. - flush caches properly, fixing visual corruptions. Changes since v4: - fix up cache flushing of overlay memory regs. - killed require_pipe_a logic - it hangs the chip. Tested-By: diego.abelenda@gmail.com (on a 865G) Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> [anholt: Resolved against the MADVISE ioctl going in before this one] Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c7
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h5
-rw-r--r--drivers/gpu/drm/i915/intel_display.c25
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h28
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c1293
7 files changed, 1361 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index fa7b9be096bc..87b21996cd6a 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -23,6 +23,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
23 intel_fb.o \ 23 intel_fb.o \
24 intel_tv.o \ 24 intel_tv.o \
25 intel_dvo.o \ 25 intel_dvo.o \
26 intel_overlay.o \
26 dvo_ch7xxx.o \ 27 dvo_ch7xxx.o \
27 dvo_ch7017.o \ 28 dvo_ch7017.o \
28 dvo_ivch.o \ 29 dvo_ivch.o \
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index e5b138be45fa..138be49259c3 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -807,6 +807,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
807 case I915_PARAM_NUM_FENCES_AVAIL: 807 case I915_PARAM_NUM_FENCES_AVAIL:
808 value = dev_priv->num_fence_regs - dev_priv->fence_reg_start; 808 value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
809 break; 809 break;
810 case I915_PARAM_HAS_OVERLAY:
811 value = dev_priv->overlay ? 1 : 0;
812 break;
810 default: 813 default:
811 DRM_DEBUG_DRIVER("Unknown parameter %d\n", 814 DRM_DEBUG_DRIVER("Unknown parameter %d\n",
812 param->param); 815 param->param);
@@ -1548,6 +1551,8 @@ int i915_driver_unload(struct drm_device *dev)
1548 mutex_unlock(&dev->struct_mutex); 1551 mutex_unlock(&dev->struct_mutex);
1549 drm_mm_takedown(&dev_priv->vram); 1552 drm_mm_takedown(&dev_priv->vram);
1550 i915_gem_lastclose(dev); 1553 i915_gem_lastclose(dev);
1554
1555 intel_cleanup_overlay(dev);
1551 } 1556 }
1552 1557
1553 pci_dev_put(dev_priv->bridge_dev); 1558 pci_dev_put(dev_priv->bridge_dev);
@@ -1656,6 +1661,8 @@ struct drm_ioctl_desc i915_ioctls[] = {
1656 DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 0), 1661 DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 0),
1657 DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0), 1662 DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
1658 DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, 0), 1663 DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, 0),
1664 DRM_IOCTL_DEF(DRM_I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW),
1665 DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW),
1659}; 1666};
1660 1667
1661int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); 1668int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4e8b26161a74..ce03fd5b3f5b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -170,6 +170,8 @@ struct drm_i915_display_funcs {
170 /* clock gating init */ 170 /* clock gating init */
171}; 171};
172 172
173struct intel_overlay;
174
173typedef struct drm_i915_private { 175typedef struct drm_i915_private {
174 struct drm_device *dev; 176 struct drm_device *dev;
175 177
@@ -241,6 +243,9 @@ typedef struct drm_i915_private {
241 243
242 struct intel_opregion opregion; 244 struct intel_opregion opregion;
243 245
246 /* overlay */
247 struct intel_overlay *overlay;
248
244 /* LVDS info */ 249 /* LVDS info */
245 int backlight_duty_cycle; /* restore backlight to this value */ 250 int backlight_duty_cycle; /* restore backlight to this value */
246 bool panel_wants_dither; 251 bool panel_wants_dither;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 51fd152f47f3..d1be1849580d 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -140,6 +140,7 @@
140#define MI_NOOP MI_INSTR(0, 0) 140#define MI_NOOP MI_INSTR(0, 0)
141#define MI_USER_INTERRUPT MI_INSTR(0x02, 0) 141#define MI_USER_INTERRUPT MI_INSTR(0x02, 0)
142#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) 142#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0)
143#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16)
143#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) 144#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6)
144#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) 145#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
145#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) 146#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
@@ -151,6 +152,10 @@
151#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ 152#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */
152#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) 153#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0)
153#define MI_REPORT_HEAD MI_INSTR(0x07, 0) 154#define MI_REPORT_HEAD MI_INSTR(0x07, 0)
155#define MI_OVERLAY_FLIP MI_INSTR(0x11,0)
156#define MI_OVERLAY_CONTINUE (0x0<<21)
157#define MI_OVERLAY_ON (0x1<<21)
158#define MI_OVERLAY_OFF (0x2<<21)
154#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) 159#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0)
155#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) 160#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
156#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ 161#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0be624a52e50..6f818fadcbe3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1781,6 +1781,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
1781 } 1781 }
1782} 1782}
1783 1783
1784static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
1785{
1786 struct intel_overlay *overlay;
1787
1788 if (!enable && intel_crtc->overlay) {
1789 overlay = intel_crtc->overlay;
1790 mutex_lock(&overlay->dev->struct_mutex);
1791 intel_overlay_switch_off(overlay);
1792 mutex_unlock(&overlay->dev->struct_mutex);
1793 }
1794 /* Let userspace switch the overlay on again. In most cases userspace
1795 * has to recompute where to put it anyway. */
1796
1797 return;
1798}
1799
1784static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) 1800static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
1785{ 1801{
1786 struct drm_device *dev = crtc->dev; 1802 struct drm_device *dev = crtc->dev;
@@ -1839,12 +1855,13 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
1839 intel_update_fbc(crtc, &crtc->mode); 1855 intel_update_fbc(crtc, &crtc->mode);
1840 1856
1841 /* Give the overlay scaler a chance to enable if it's on this pipe */ 1857 /* Give the overlay scaler a chance to enable if it's on this pipe */
1842 //intel_crtc_dpms_video(crtc, true); TODO 1858 intel_crtc_dpms_overlay(intel_crtc, true);
1843 break; 1859 break;
1844 case DRM_MODE_DPMS_OFF: 1860 case DRM_MODE_DPMS_OFF:
1845 intel_update_watermarks(dev); 1861 intel_update_watermarks(dev);
1862
1846 /* Give the overlay scaler a chance to disable if it's on this pipe */ 1863 /* Give the overlay scaler a chance to disable if it's on this pipe */
1847 //intel_crtc_dpms_video(crtc, FALSE); TODO 1864 intel_crtc_dpms_overlay(intel_crtc, false);
1848 1865
1849 if (dev_priv->cfb_plane == plane && 1866 if (dev_priv->cfb_plane == plane &&
1850 dev_priv->display.disable_fbc) 1867 dev_priv->display.disable_fbc)
@@ -2039,7 +2056,7 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
2039 * Return the pipe currently connected to the panel fitter, 2056 * Return the pipe currently connected to the panel fitter,
2040 * or -1 if the panel fitter is not present or not in use 2057 * or -1 if the panel fitter is not present or not in use
2041 */ 2058 */
2042static int intel_panel_fitter_pipe (struct drm_device *dev) 2059int intel_panel_fitter_pipe (struct drm_device *dev)
2043{ 2060{
2044 struct drm_i915_private *dev_priv = dev->dev_private; 2061 struct drm_i915_private *dev_priv = dev->dev_private;
2045 u32 pfit_control; 2062 u32 pfit_control;
@@ -4458,6 +4475,8 @@ void intel_modeset_init(struct drm_device *dev)
4458 INIT_WORK(&dev_priv->idle_work, intel_idle_update); 4475 INIT_WORK(&dev_priv->idle_work, intel_idle_update);
4459 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, 4476 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
4460 (unsigned long)dev); 4477 (unsigned long)dev);
4478
4479 intel_setup_overlay(dev);
4461} 4480}
4462 4481
4463void intel_modeset_cleanup(struct drm_device *dev) 4482void intel_modeset_cleanup(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ef61fe9507e2..c9b1b97ab792 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -110,6 +110,25 @@ struct intel_output {
110 int clone_mask; 110 int clone_mask;
111}; 111};
112 112
113struct intel_crtc;
114struct intel_overlay {
115 struct drm_device *dev;
116 struct intel_crtc *crtc;
117 struct drm_i915_gem_object *vid_bo;
118 struct drm_i915_gem_object *old_vid_bo;
119 int active;
120 int pfit_active;
121 u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
122 u32 color_key;
123 u32 brightness, contrast, saturation;
124 u32 old_xscale, old_yscale;
125 /* register access */
126 u32 flip_addr;
127 struct drm_i915_gem_object *reg_bo;
128 void *virt_addr;
129 int hw_wedged;
130};
131
113struct intel_crtc { 132struct intel_crtc {
114 struct drm_crtc base; 133 struct drm_crtc base;
115 enum pipe pipe; 134 enum pipe pipe;
@@ -121,6 +140,7 @@ struct intel_crtc {
121 bool busy; /* is scanout buffer being updated frequently? */ 140 bool busy; /* is scanout buffer being updated frequently? */
122 struct timer_list idle_timer; 141 struct timer_list idle_timer;
123 bool lowfreq_avail; 142 bool lowfreq_avail;
143 struct intel_overlay *overlay;
124}; 144};
125 145
126#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) 146#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
@@ -148,6 +168,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
148extern void intel_edp_link_config (struct intel_output *, int *, int *); 168extern void intel_edp_link_config (struct intel_output *, int *, int *);
149 169
150 170
171extern int intel_panel_fitter_pipe (struct drm_device *dev);
151extern void intel_crtc_load_lut(struct drm_crtc *crtc); 172extern void intel_crtc_load_lut(struct drm_crtc *crtc);
152extern void intel_encoder_prepare (struct drm_encoder *encoder); 173extern void intel_encoder_prepare (struct drm_encoder *encoder);
153extern void intel_encoder_commit (struct drm_encoder *encoder); 174extern void intel_encoder_commit (struct drm_encoder *encoder);
@@ -183,4 +204,11 @@ extern int intel_framebuffer_create(struct drm_device *dev,
183 struct drm_framebuffer **fb, 204 struct drm_framebuffer **fb,
184 struct drm_gem_object *obj); 205 struct drm_gem_object *obj);
185 206
207extern void intel_setup_overlay(struct drm_device *dev);
208extern void intel_cleanup_overlay(struct drm_device *dev);
209extern int intel_overlay_switch_off(struct intel_overlay *overlay);
210extern int intel_overlay_put_image(struct drm_device *dev, void *data,
211 struct drm_file *file_priv);
212extern int intel_overlay_attrs(struct drm_device *dev, void *data,
213 struct drm_file *file_priv);
186#endif /* __INTEL_DRV_H__ */ 214#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
new file mode 100644
index 000000000000..3f6f3a36929f
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -0,0 +1,1293 @@
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 */
28#include "drmP.h"
29#include "drm.h"
30#include "i915_drm.h"
31#include "i915_drv.h"
32#include "i915_reg.h"
33#include "intel_drv.h"
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)
68#define OCMD_BUF_TYPE_MASK (Ox1<<5)
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 {
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];
169};
170
171/* overlay flip addr flag */
172#define OFC_UPDATE 0x1
173
174#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
175#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IGDNG(dev))
176
177
178static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
179{
180 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
181 struct overlay_registers *regs;
182
183 /* no recursive mappings */
184 BUG_ON(overlay->virt_addr);
185
186 if (OVERLAY_NONPHYSICAL(overlay->dev)) {
187 regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
188 overlay->reg_bo->gtt_offset);
189
190 if (!regs) {
191 DRM_ERROR("failed to map overlay regs in GTT\n");
192 return NULL;
193 }
194 } else
195 regs = overlay->reg_bo->phys_obj->handle->vaddr;
196
197 return overlay->virt_addr = regs;
198}
199
200static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
201{
202 struct drm_device *dev = overlay->dev;
203 drm_i915_private_t *dev_priv = dev->dev_private;
204
205 if (OVERLAY_NONPHYSICAL(overlay->dev))
206 io_mapping_unmap_atomic(overlay->virt_addr);
207
208 overlay->virt_addr = NULL;
209
210 I915_READ(OVADD); /* flush wc cashes */
211
212 return;
213}
214
215/* overlay needs to be disable in OCMD reg */
216static int intel_overlay_on(struct intel_overlay *overlay)
217{
218 struct drm_device *dev = overlay->dev;
219 drm_i915_private_t *dev_priv = dev->dev_private;
220 int ret;
221 RING_LOCALS;
222
223 BUG_ON(overlay->active);
224
225 BEGIN_LP_RING(6);
226 OUT_RING(MI_FLUSH);
227 OUT_RING(MI_NOOP);
228 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
229 OUT_RING(overlay->flip_addr | OFC_UPDATE);
230 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
231 OUT_RING(MI_NOOP);
232 ADVANCE_LP_RING();
233
234 ret = i915_lp_ring_sync(dev);
235 if (ret != 0) {
236 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
237 overlay->hw_wedged = 1;
238 return 0;
239 }
240
241 overlay->active = 1;
242
243 return 0;
244}
245
246/* overlay needs to be enabled in OCMD reg */
247static void intel_overlay_continue(struct intel_overlay *overlay,
248 bool load_polyphase_filter)
249{
250 struct drm_device *dev = overlay->dev;
251 drm_i915_private_t *dev_priv = dev->dev_private;
252 u32 flip_addr = overlay->flip_addr;
253 u32 tmp;
254 int ret;
255 RING_LOCALS;
256
257 BUG_ON(!overlay->active);
258
259 if (load_polyphase_filter)
260 flip_addr |= OFC_UPDATE;
261
262 /* check for underruns */
263 tmp = I915_READ(DOVSTA);
264 if (tmp & (1 << 17))
265 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
266
267 BEGIN_LP_RING(6);
268 OUT_RING(MI_FLUSH);
269 OUT_RING(MI_NOOP);
270 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
271 OUT_RING(flip_addr);
272 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
273 OUT_RING(MI_NOOP);
274 ADVANCE_LP_RING();
275
276 /* run in lockstep with the hw for easier testing */
277 ret = i915_lp_ring_sync(dev);
278 if (ret != 0) {
279 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
280 overlay->hw_wedged = 1;
281 }
282}
283
284static int intel_overlay_wait_flip(struct intel_overlay *overlay)
285{
286 /* don't overcomplicate things for now with asynchronous operations
287 * see comment above */
288 return 0;
289}
290
291/* overlay needs to be disabled in OCMD reg */
292static int intel_overlay_off(struct intel_overlay *overlay)
293{
294 u32 flip_addr = overlay->flip_addr;
295 struct drm_device *dev = overlay->dev;
296 drm_i915_private_t *dev_priv = dev->dev_private;
297 int ret;
298 RING_LOCALS;
299
300 BUG_ON(!overlay->active);
301
302 /* According to intel docs the overlay hw may hang (when switching
303 * off) without loading the filter coeffs. It is however unclear whether
304 * this applies to the disabling of the overlay or to the switching off
305 * of the hw. Do it in both cases */
306 flip_addr |= OFC_UPDATE;
307
308 /* wait for overlay to go idle */
309 BEGIN_LP_RING(6);
310 OUT_RING(MI_FLUSH);
311 OUT_RING(MI_NOOP);
312 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
313 OUT_RING(flip_addr);
314 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
315 OUT_RING(MI_NOOP);
316 ADVANCE_LP_RING();
317
318 ret = i915_lp_ring_sync(dev);
319 if (ret != 0) {
320 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
321 overlay->hw_wedged = 1;
322 return ret;
323 }
324
325 /* turn overlay off */
326 /* this is not done in userspace!
327 BEGIN_LP_RING(6);
328 OUT_RING(MI_FLUSH);
329 OUT_RING(MI_NOOP);
330 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
331 OUT_RING(flip_addr);
332 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
333 OUT_RING(MI_NOOP);
334 ADVANCE_LP_RING();
335
336 ret = i915_lp_ring_sync(dev);
337 if (ret != 0) {
338 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
339 overlay->hw_wedged = 1;
340 return ret;
341 }*/
342
343 overlay->active = 0;
344
345 return ret;
346}
347
348/* wait for pending overlay flip and release old frame */
349static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
350{
351 int ret;
352 struct drm_gem_object *obj;
353
354 ret = intel_overlay_wait_flip(overlay);
355 if (ret != 0)
356 return ret;
357
358 if (!overlay->old_vid_bo)
359 return 0;
360
361 obj = overlay->old_vid_bo->obj;
362 i915_gem_object_unpin(obj);
363 drm_gem_object_unreference(obj);
364 overlay->old_vid_bo = NULL;
365
366 return 0;
367}
368
369struct put_image_params {
370 int format;
371 short dst_x;
372 short dst_y;
373 short dst_w;
374 short dst_h;
375 short src_w;
376 short src_scan_h;
377 short src_scan_w;
378 short src_h;
379 short stride_Y;
380 short stride_UV;
381 int offset_Y;
382 int offset_U;
383 int offset_V;
384};
385
386static int packed_depth_bytes(u32 format)
387{
388 switch (format & I915_OVERLAY_DEPTH_MASK) {
389 case I915_OVERLAY_YUV422:
390 return 4;
391 case I915_OVERLAY_YUV411:
392 /* return 6; not implemented */
393 default:
394 return -EINVAL;
395 }
396}
397
398static int packed_width_bytes(u32 format, short width)
399{
400 switch (format & I915_OVERLAY_DEPTH_MASK) {
401 case I915_OVERLAY_YUV422:
402 return width << 1;
403 default:
404 return -EINVAL;
405 }
406}
407
408static int uv_hsubsampling(u32 format)
409{
410 switch (format & I915_OVERLAY_DEPTH_MASK) {
411 case I915_OVERLAY_YUV422:
412 case I915_OVERLAY_YUV420:
413 return 2;
414 case I915_OVERLAY_YUV411:
415 case I915_OVERLAY_YUV410:
416 return 4;
417 default:
418 return -EINVAL;
419 }
420}
421
422static int uv_vsubsampling(u32 format)
423{
424 switch (format & I915_OVERLAY_DEPTH_MASK) {
425 case I915_OVERLAY_YUV420:
426 case I915_OVERLAY_YUV410:
427 return 2;
428 case I915_OVERLAY_YUV422:
429 case I915_OVERLAY_YUV411:
430 return 1;
431 default:
432 return -EINVAL;
433 }
434}
435
436static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
437{
438 u32 mask, shift, ret;
439 if (IS_I9XX(dev)) {
440 mask = 0x3f;
441 shift = 6;
442 } else {
443 mask = 0x1f;
444 shift = 5;
445 }
446 ret = ((offset + width + mask) >> shift) - (offset >> shift);
447 if (IS_I9XX(dev))
448 ret <<= 1;
449 ret -=1;
450 return ret << 2;
451}
452
453static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
454 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
455 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
456 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
457 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
458 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
459 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
460 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
461 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
462 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
463 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
464 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
465 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
466 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
467 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
468 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
469 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
470 0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
471static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
472 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
473 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
474 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
475 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
476 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
477 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
478 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
479 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
480 0x3000, 0x0800, 0x3000};
481
482static void update_polyphase_filter(struct overlay_registers *regs)
483{
484 memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
485 memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
486}
487
488static bool update_scaling_factors(struct intel_overlay *overlay,
489 struct overlay_registers *regs,
490 struct put_image_params *params)
491{
492 /* fixed point with a 12 bit shift */
493 u32 xscale, yscale, xscale_UV, yscale_UV;
494#define FP_SHIFT 12
495#define FRACT_MASK 0xfff
496 bool scale_changed = false;
497 int uv_hscale = uv_hsubsampling(params->format);
498 int uv_vscale = uv_vsubsampling(params->format);
499
500 if (params->dst_w > 1)
501 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
502 /(params->dst_w);
503 else
504 xscale = 1 << FP_SHIFT;
505
506 if (params->dst_h > 1)
507 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
508 /(params->dst_h);
509 else
510 yscale = 1 << FP_SHIFT;
511
512 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
513 xscale_UV = xscale/uv_hscale;
514 yscale_UV = yscale/uv_vscale;
515 /* make the Y scale to UV scale ratio an exact multiply */
516 xscale = xscale_UV * uv_hscale;
517 yscale = yscale_UV * uv_vscale;
518 /*} else {
519 xscale_UV = 0;
520 yscale_UV = 0;
521 }*/
522
523 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
524 scale_changed = true;
525 overlay->old_xscale = xscale;
526 overlay->old_yscale = yscale;
527
528 regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
529 | ((xscale >> FP_SHIFT) << 16)
530 | ((xscale & FRACT_MASK) << 3);
531 regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
532 | ((xscale_UV >> FP_SHIFT) << 16)
533 | ((xscale_UV & FRACT_MASK) << 3);
534 regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
535 | ((yscale_UV >> FP_SHIFT) << 0);
536
537 if (scale_changed)
538 update_polyphase_filter(regs);
539
540 return scale_changed;
541}
542
543static void update_colorkey(struct intel_overlay *overlay,
544 struct overlay_registers *regs)
545{
546 u32 key = overlay->color_key;
547 switch (overlay->crtc->base.fb->bits_per_pixel) {
548 case 8:
549 regs->DCLRKV = 0;
550 regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
551 case 16:
552 if (overlay->crtc->base.fb->depth == 15) {
553 regs->DCLRKV = RGB15_TO_COLORKEY(key);
554 regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
555 } else {
556 regs->DCLRKV = RGB16_TO_COLORKEY(key);
557 regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
558 }
559 case 24:
560 case 32:
561 regs->DCLRKV = key;
562 regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
563 }
564}
565
566static u32 overlay_cmd_reg(struct put_image_params *params)
567{
568 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
569
570 if (params->format & I915_OVERLAY_YUV_PLANAR) {
571 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
572 case I915_OVERLAY_YUV422:
573 cmd |= OCMD_YUV_422_PLANAR;
574 break;
575 case I915_OVERLAY_YUV420:
576 cmd |= OCMD_YUV_420_PLANAR;
577 break;
578 case I915_OVERLAY_YUV411:
579 case I915_OVERLAY_YUV410:
580 cmd |= OCMD_YUV_410_PLANAR;
581 break;
582 }
583 } else { /* YUV packed */
584 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
585 case I915_OVERLAY_YUV422:
586 cmd |= OCMD_YUV_422_PACKED;
587 break;
588 case I915_OVERLAY_YUV411:
589 cmd |= OCMD_YUV_411_PACKED;
590 break;
591 }
592
593 switch (params->format & I915_OVERLAY_SWAP_MASK) {
594 case I915_OVERLAY_NO_SWAP:
595 break;
596 case I915_OVERLAY_UV_SWAP:
597 cmd |= OCMD_UV_SWAP;
598 break;
599 case I915_OVERLAY_Y_SWAP:
600 cmd |= OCMD_Y_SWAP;
601 break;
602 case I915_OVERLAY_Y_AND_UV_SWAP:
603 cmd |= OCMD_Y_AND_UV_SWAP;
604 break;
605 }
606 }
607
608 return cmd;
609}
610
611int intel_overlay_do_put_image(struct intel_overlay *overlay,
612 struct drm_gem_object *new_bo,
613 struct put_image_params *params)
614{
615 int ret, tmp_width;
616 struct overlay_registers *regs;
617 bool scale_changed = false;
618 struct drm_i915_gem_object *bo_priv = new_bo->driver_private;
619 struct drm_device *dev = overlay->dev;
620
621 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
622 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
623 BUG_ON(!overlay);
624
625 if (overlay->hw_wedged)
626 return -EBUSY;
627
628 ret = intel_overlay_release_old_vid(overlay);
629 if (ret != 0)
630 return ret;
631
632 ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
633 if (ret != 0)
634 return ret;
635
636 ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
637 if (ret != 0)
638 goto out_unpin;
639
640 if (!overlay->active) {
641 regs = intel_overlay_map_regs_atomic(overlay);
642 if (!regs) {
643 ret = -ENOMEM;
644 goto out_unpin;
645 }
646 regs->OCONFIG = OCONF_CC_OUT_8BIT;
647 if (IS_I965GM(overlay->dev))
648 regs->OCONFIG |= OCONF_CSC_MODE_BT709;
649 regs->OCONFIG |= overlay->crtc->pipe == 0 ?
650 OCONF_PIPE_A : OCONF_PIPE_B;
651 intel_overlay_unmap_regs_atomic(overlay);
652
653 ret = intel_overlay_on(overlay);
654 if (ret != 0)
655 goto out_unpin;
656 }
657
658 regs = intel_overlay_map_regs_atomic(overlay);
659 if (!regs) {
660 ret = -ENOMEM;
661 goto out_unpin;
662 }
663
664 regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
665 regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
666
667 if (params->format & I915_OVERLAY_YUV_PACKED)
668 tmp_width = packed_width_bytes(params->format, params->src_w);
669 else
670 tmp_width = params->src_w;
671
672 regs->SWIDTH = params->src_w;
673 regs->SWIDTHSW = calc_swidthsw(overlay->dev,
674 params->offset_Y, tmp_width);
675 regs->SHEIGHT = params->src_h;
676 regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
677 regs->OSTRIDE = params->stride_Y;
678
679 if (params->format & I915_OVERLAY_YUV_PLANAR) {
680 int uv_hscale = uv_hsubsampling(params->format);
681 int uv_vscale = uv_vsubsampling(params->format);
682 u32 tmp_U, tmp_V;
683 regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
684 tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
685 params->src_w/uv_hscale);
686 tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
687 params->src_w/uv_hscale);
688 regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
689 regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
690 regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
691 regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V;
692 regs->OSTRIDE |= params->stride_UV << 16;
693 }
694
695 scale_changed = update_scaling_factors(overlay, regs, params);
696
697 update_colorkey(overlay, regs);
698
699 regs->OCMD = overlay_cmd_reg(params);
700
701 intel_overlay_unmap_regs_atomic(overlay);
702
703 intel_overlay_continue(overlay, scale_changed);
704
705 overlay->old_vid_bo = overlay->vid_bo;
706 overlay->vid_bo = new_bo->driver_private;
707
708 return 0;
709
710out_unpin:
711 i915_gem_object_unpin(new_bo);
712 return ret;
713}
714
715int intel_overlay_switch_off(struct intel_overlay *overlay)
716{
717 int ret;
718 struct overlay_registers *regs;
719 struct drm_gem_object *obj;
720 struct drm_device *dev = overlay->dev;
721
722 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
723 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
724
725 if (!overlay->active)
726 return 0;
727
728 if (overlay->hw_wedged)
729 return -EBUSY;
730
731 ret = intel_overlay_release_old_vid(overlay);
732 if (ret != 0)
733 return ret;
734
735 regs = intel_overlay_map_regs_atomic(overlay);
736 regs->OCMD = 0;
737 intel_overlay_unmap_regs_atomic(overlay);
738
739 ret = intel_overlay_off(overlay);
740 /* never have the overlay hw on without showing a frame */
741 BUG_ON(!overlay->vid_bo);
742 obj = overlay->vid_bo->obj;
743
744 i915_gem_object_unpin(obj);
745 drm_gem_object_unreference(obj);
746 overlay->vid_bo = NULL;
747
748 overlay->crtc->overlay = NULL;
749 overlay->crtc = NULL;
750
751 return 0;
752}
753
754static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
755 struct intel_crtc *crtc)
756{
757 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
758 u32 pipeconf;
759 int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
760
761 if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
762 return -EINVAL;
763
764 pipeconf = I915_READ(pipeconf_reg);
765
766 /* can't use the overlay with double wide pipe */
767 if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
768 return -EINVAL;
769
770 return 0;
771}
772
773static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
774{
775 struct drm_device *dev = overlay->dev;
776 drm_i915_private_t *dev_priv = dev->dev_private;
777 u32 ratio;
778 u32 pfit_control = I915_READ(PFIT_CONTROL);
779
780 /* XXX: This is not the same logic as in the xorg driver, but more in
781 * line with the intel documentation for the i965 */
782 if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
783 ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
784 } else { /* on i965 use the PGM reg to read out the autoscaler values */
785 ratio = I915_READ(PFIT_PGM_RATIOS);
786 if (IS_I965G(dev))
787 ratio >>= PFIT_VERT_SCALE_SHIFT_965;
788 else
789 ratio >>= PFIT_VERT_SCALE_SHIFT;
790 }
791
792 overlay->pfit_vscale_ratio = ratio;
793}
794
795static int check_overlay_dst(struct intel_overlay *overlay,
796 struct drm_intel_overlay_put_image *rec)
797{
798 struct drm_display_mode *mode = &overlay->crtc->base.mode;
799
800 if ((rec->dst_x < mode->crtc_hdisplay)
801 && (rec->dst_x + rec->dst_width
802 <= mode->crtc_hdisplay)
803 && (rec->dst_y < mode->crtc_vdisplay)
804 && (rec->dst_y + rec->dst_height
805 <= mode->crtc_vdisplay))
806 return 0;
807 else
808 return -EINVAL;
809}
810
811static int check_overlay_scaling(struct put_image_params *rec)
812{
813 u32 tmp;
814
815 /* downscaling limit is 8.0 */
816 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
817 if (tmp > 7)
818 return -EINVAL;
819 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
820 if (tmp > 7)
821 return -EINVAL;
822
823 return 0;
824}
825
826static int check_overlay_src(struct drm_device *dev,
827 struct drm_intel_overlay_put_image *rec,
828 struct drm_gem_object *new_bo)
829{
830 u32 stride_mask;
831 int depth;
832 int uv_hscale = uv_hsubsampling(rec->flags);
833 int uv_vscale = uv_vsubsampling(rec->flags);
834 size_t tmp;
835
836 /* check src dimensions */
837 if (IS_845G(dev) || IS_I830(dev)) {
838 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
839 || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
840 return -EINVAL;
841 } else {
842 if (rec->src_height > IMAGE_MAX_HEIGHT
843 || rec->src_width > IMAGE_MAX_WIDTH)
844 return -EINVAL;
845 }
846 /* better safe than sorry, use 4 as the maximal subsampling ratio */
847 if (rec->src_height < N_VERT_Y_TAPS*4
848 || rec->src_width < N_HORIZ_Y_TAPS*4)
849 return -EINVAL;
850
851 /* check alingment constrains */
852 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
853 case I915_OVERLAY_RGB:
854 /* not implemented */
855 return -EINVAL;
856 case I915_OVERLAY_YUV_PACKED:
857 depth = packed_depth_bytes(rec->flags);
858 if (uv_vscale != 1)
859 return -EINVAL;
860 if (depth < 0)
861 return depth;
862 /* ignore UV planes */
863 rec->stride_UV = 0;
864 rec->offset_U = 0;
865 rec->offset_V = 0;
866 /* check pixel alignment */
867 if (rec->offset_Y % depth)
868 return -EINVAL;
869 break;
870 case I915_OVERLAY_YUV_PLANAR:
871 if (uv_vscale < 0 || uv_hscale < 0)
872 return -EINVAL;
873 /* no offset restrictions for planar formats */
874 break;
875 default:
876 return -EINVAL;
877 }
878
879 if (rec->src_width % uv_hscale)
880 return -EINVAL;
881
882 /* stride checking */
883 stride_mask = 63;
884
885 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
886 return -EINVAL;
887 if (IS_I965G(dev) && rec->stride_Y < 512)
888 return -EINVAL;
889
890 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
891 4 : 8;
892 if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
893 return -EINVAL;
894
895 /* check buffer dimensions */
896 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
897 case I915_OVERLAY_RGB:
898 case I915_OVERLAY_YUV_PACKED:
899 /* always 4 Y values per depth pixels */
900 if (packed_width_bytes(rec->flags, rec->src_width)
901 > rec->stride_Y)
902 return -EINVAL;
903
904 tmp = rec->stride_Y*rec->src_height;
905 if (rec->offset_Y + tmp > new_bo->size)
906 return -EINVAL;
907 break;
908 case I915_OVERLAY_YUV_PLANAR:
909 if (rec->src_width > rec->stride_Y)
910 return -EINVAL;
911 if (rec->src_width/uv_hscale > rec->stride_UV)
912 return -EINVAL;
913
914 tmp = rec->stride_Y*rec->src_height;
915 if (rec->offset_Y + tmp > new_bo->size)
916 return -EINVAL;
917 tmp = rec->stride_UV*rec->src_height;
918 tmp /= uv_vscale;
919 if (rec->offset_U + tmp > new_bo->size
920 || rec->offset_V + tmp > new_bo->size)
921 return -EINVAL;
922 break;
923 }
924
925 return 0;
926}
927
928int intel_overlay_put_image(struct drm_device *dev, void *data,
929 struct drm_file *file_priv)
930{
931 struct drm_intel_overlay_put_image *put_image_rec = data;
932 drm_i915_private_t *dev_priv = dev->dev_private;
933 struct intel_overlay *overlay;
934 struct drm_mode_object *drmmode_obj;
935 struct intel_crtc *crtc;
936 struct drm_gem_object *new_bo;
937 struct put_image_params *params;
938 int ret;
939
940 if (!dev_priv) {
941 DRM_ERROR("called with no initialization\n");
942 return -EINVAL;
943 }
944
945 overlay = dev_priv->overlay;
946 if (!overlay) {
947 DRM_DEBUG("userspace bug: no overlay\n");
948 return -ENODEV;
949 }
950
951 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
952 mutex_lock(&dev->mode_config.mutex);
953 mutex_lock(&dev->struct_mutex);
954
955 ret = intel_overlay_switch_off(overlay);
956
957 mutex_unlock(&dev->struct_mutex);
958 mutex_unlock(&dev->mode_config.mutex);
959
960 return ret;
961 }
962
963 params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);
964 if (!params)
965 return -ENOMEM;
966
967 drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
968 DRM_MODE_OBJECT_CRTC);
969 if (!drmmode_obj)
970 return -ENOENT;
971 crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
972
973 new_bo = drm_gem_object_lookup(dev, file_priv,
974 put_image_rec->bo_handle);
975 if (!new_bo)
976 return -ENOENT;
977
978 mutex_lock(&dev->mode_config.mutex);
979 mutex_lock(&dev->struct_mutex);
980
981 if (overlay->crtc != crtc) {
982 struct drm_display_mode *mode = &crtc->base.mode;
983 ret = intel_overlay_switch_off(overlay);
984 if (ret != 0)
985 goto out_unlock;
986
987 ret = check_overlay_possible_on_crtc(overlay, crtc);
988 if (ret != 0)
989 goto out_unlock;
990
991 overlay->crtc = crtc;
992 crtc->overlay = overlay;
993
994 if (intel_panel_fitter_pipe(dev) == crtc->pipe
995 /* and line to wide, i.e. one-line-mode */
996 && mode->hdisplay > 1024) {
997 overlay->pfit_active = 1;
998 update_pfit_vscale_ratio(overlay);
999 } else
1000 overlay->pfit_active = 0;
1001 }
1002
1003 ret = check_overlay_dst(overlay, put_image_rec);
1004 if (ret != 0)
1005 goto out_unlock;
1006
1007 if (overlay->pfit_active) {
1008 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1009 overlay->pfit_vscale_ratio);
1010 /* shifting right rounds downwards, so add 1 */
1011 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1012 overlay->pfit_vscale_ratio) + 1;
1013 } else {
1014 params->dst_y = put_image_rec->dst_y;
1015 params->dst_h = put_image_rec->dst_height;
1016 }
1017 params->dst_x = put_image_rec->dst_x;
1018 params->dst_w = put_image_rec->dst_width;
1019
1020 params->src_w = put_image_rec->src_width;
1021 params->src_h = put_image_rec->src_height;
1022 params->src_scan_w = put_image_rec->src_scan_width;
1023 params->src_scan_h = put_image_rec->src_scan_height;
1024 if (params->src_scan_h > params->src_h
1025 || params->src_scan_w > params->src_w) {
1026 ret = -EINVAL;
1027 goto out_unlock;
1028 }
1029
1030 ret = check_overlay_src(dev, put_image_rec, new_bo);
1031 if (ret != 0)
1032 goto out_unlock;
1033 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1034 params->stride_Y = put_image_rec->stride_Y;
1035 params->stride_UV = put_image_rec->stride_UV;
1036 params->offset_Y = put_image_rec->offset_Y;
1037 params->offset_U = put_image_rec->offset_U;
1038 params->offset_V = put_image_rec->offset_V;
1039
1040 /* Check scaling after src size to prevent a divide-by-zero. */
1041 ret = check_overlay_scaling(params);
1042 if (ret != 0)
1043 goto out_unlock;
1044
1045 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1046 if (ret != 0)
1047 goto out_unlock;
1048
1049 mutex_unlock(&dev->struct_mutex);
1050 mutex_unlock(&dev->mode_config.mutex);
1051
1052 kfree(params);
1053
1054 return 0;
1055
1056out_unlock:
1057 mutex_unlock(&dev->struct_mutex);
1058 mutex_unlock(&dev->mode_config.mutex);
1059 drm_gem_object_unreference(new_bo);
1060 kfree(params);
1061
1062 return ret;
1063}
1064
1065static void update_reg_attrs(struct intel_overlay *overlay,
1066 struct overlay_registers *regs)
1067{
1068 regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1069 regs->OCLRC1 = overlay->saturation;
1070}
1071
1072static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1073{
1074 int i;
1075
1076 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1077 return false;
1078
1079 for (i = 0; i < 3; i++) {
1080 if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1081 return false;
1082 }
1083
1084 return true;
1085}
1086
1087static bool check_gamma5_errata(u32 gamma5)
1088{
1089 int i;
1090
1091 for (i = 0; i < 3; i++) {
1092 if (((gamma5 >> i*8) & 0xff) == 0x80)
1093 return false;
1094 }
1095
1096 return true;
1097}
1098
1099static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1100{
1101 if (!check_gamma_bounds(0, attrs->gamma0)
1102 || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
1103 || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
1104 || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
1105 || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
1106 || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
1107 || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1108 return -EINVAL;
1109 if (!check_gamma5_errata(attrs->gamma5))
1110 return -EINVAL;
1111 return 0;
1112}
1113
1114int intel_overlay_attrs(struct drm_device *dev, void *data,
1115 struct drm_file *file_priv)
1116{
1117 struct drm_intel_overlay_attrs *attrs = data;
1118 drm_i915_private_t *dev_priv = dev->dev_private;
1119 struct intel_overlay *overlay;
1120 struct overlay_registers *regs;
1121 int ret;
1122
1123 if (!dev_priv) {
1124 DRM_ERROR("called with no initialization\n");
1125 return -EINVAL;
1126 }
1127
1128 overlay = dev_priv->overlay;
1129 if (!overlay) {
1130 DRM_DEBUG("userspace bug: no overlay\n");
1131 return -ENODEV;
1132 }
1133
1134 mutex_lock(&dev->mode_config.mutex);
1135 mutex_lock(&dev->struct_mutex);
1136
1137 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1138 attrs->color_key = overlay->color_key;
1139 attrs->brightness = overlay->brightness;
1140 attrs->contrast = overlay->contrast;
1141 attrs->saturation = overlay->saturation;
1142
1143 if (IS_I9XX(dev)) {
1144 attrs->gamma0 = I915_READ(OGAMC0);
1145 attrs->gamma1 = I915_READ(OGAMC1);
1146 attrs->gamma2 = I915_READ(OGAMC2);
1147 attrs->gamma3 = I915_READ(OGAMC3);
1148 attrs->gamma4 = I915_READ(OGAMC4);
1149 attrs->gamma5 = I915_READ(OGAMC5);
1150 }
1151 ret = 0;
1152 } else {
1153 overlay->color_key = attrs->color_key;
1154 if (attrs->brightness >= -128 && attrs->brightness <= 127) {
1155 overlay->brightness = attrs->brightness;
1156 } else {
1157 ret = -EINVAL;
1158 goto out_unlock;
1159 }
1160 if (attrs->contrast <= 255) {
1161 overlay->contrast = attrs->contrast;
1162 } else {
1163 ret = -EINVAL;
1164 goto out_unlock;
1165 }
1166 if (attrs->saturation <= 1023) {
1167 overlay->saturation = attrs->saturation;
1168 } else {
1169 ret = -EINVAL;
1170 goto out_unlock;
1171 }
1172
1173 regs = intel_overlay_map_regs_atomic(overlay);
1174 if (!regs) {
1175 ret = -ENOMEM;
1176 goto out_unlock;
1177 }
1178
1179 update_reg_attrs(overlay, regs);
1180
1181 intel_overlay_unmap_regs_atomic(overlay);
1182
1183 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1184 if (!IS_I9XX(dev)) {
1185 ret = -EINVAL;
1186 goto out_unlock;
1187 }
1188
1189 if (overlay->active) {
1190 ret = -EBUSY;
1191 goto out_unlock;
1192 }
1193
1194 ret = check_gamma(attrs);
1195 if (ret != 0)
1196 goto out_unlock;
1197
1198 I915_WRITE(OGAMC0, attrs->gamma0);
1199 I915_WRITE(OGAMC1, attrs->gamma1);
1200 I915_WRITE(OGAMC2, attrs->gamma2);
1201 I915_WRITE(OGAMC3, attrs->gamma3);
1202 I915_WRITE(OGAMC4, attrs->gamma4);
1203 I915_WRITE(OGAMC5, attrs->gamma5);
1204 }
1205 ret = 0;
1206 }
1207
1208out_unlock:
1209 mutex_unlock(&dev->struct_mutex);
1210 mutex_unlock(&dev->mode_config.mutex);
1211
1212 return ret;
1213}
1214
1215void intel_setup_overlay(struct drm_device *dev)
1216{
1217 drm_i915_private_t *dev_priv = dev->dev_private;
1218 struct intel_overlay *overlay;
1219 struct drm_gem_object *reg_bo;
1220 struct overlay_registers *regs;
1221 int ret;
1222
1223 if (!OVERLAY_EXISTS(dev))
1224 return;
1225
1226 overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
1227 if (!overlay)
1228 return;
1229 overlay->dev = dev;
1230
1231 reg_bo = drm_gem_object_alloc(dev, PAGE_SIZE);
1232 if (!reg_bo)
1233 goto out_free;
1234 overlay->reg_bo = reg_bo->driver_private;
1235
1236 if (OVERLAY_NONPHYSICAL(dev)) {
1237 ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
1238 if (ret) {
1239 DRM_ERROR("failed to pin overlay register bo\n");
1240 goto out_free_bo;
1241 }
1242 overlay->flip_addr = overlay->reg_bo->gtt_offset;
1243 } else {
1244 ret = i915_gem_attach_phys_object(dev, reg_bo,
1245 I915_GEM_PHYS_OVERLAY_REGS);
1246 if (ret) {
1247 DRM_ERROR("failed to attach phys overlay regs\n");
1248 goto out_free_bo;
1249 }
1250 overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
1251 }
1252
1253 /* init all values */
1254 overlay->color_key = 0x0101fe;
1255 overlay->brightness = -19;
1256 overlay->contrast = 75;
1257 overlay->saturation = 146;
1258
1259 regs = intel_overlay_map_regs_atomic(overlay);
1260 if (!regs)
1261 goto out_free_bo;
1262
1263 memset(regs, 0, sizeof(struct overlay_registers));
1264 update_polyphase_filter(regs);
1265
1266 update_reg_attrs(overlay, regs);
1267
1268 intel_overlay_unmap_regs_atomic(overlay);
1269
1270 dev_priv->overlay = overlay;
1271 DRM_INFO("initialized overlay support\n");
1272 return;
1273
1274out_free_bo:
1275 drm_gem_object_unreference(reg_bo);
1276out_free:
1277 kfree(overlay);
1278 return;
1279}
1280
1281void intel_cleanup_overlay(struct drm_device *dev)
1282{
1283 drm_i915_private_t *dev_priv = dev->dev_private;
1284
1285 if (dev_priv->overlay) {
1286 /* The bo's should be free'd by the generic code already.
1287 * Furthermore modesetting teardown happens beforehand so the
1288 * hardware should be off already */
1289 BUG_ON(dev_priv->overlay->active);
1290
1291 kfree(dev_priv->overlay);
1292 }
1293}