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