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; 175e3adcf8fSFrançois Tigeot int active; 176e3adcf8fSFrançois Tigeot int pfit_active; 177e3adcf8fSFrançois Tigeot u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ 178e3adcf8fSFrançois Tigeot u32 color_key; 179e3adcf8fSFrançois Tigeot u32 brightness, contrast, saturation; 180e3adcf8fSFrançois Tigeot u32 old_xscale, old_yscale; 181e3adcf8fSFrançois Tigeot /* register access */ 182e3adcf8fSFrançois Tigeot u32 flip_addr; 183e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *reg_bo; 184e3adcf8fSFrançois Tigeot /* flip handling */ 185e3adcf8fSFrançois Tigeot uint32_t last_flip_req; 186e3adcf8fSFrançois Tigeot void (*flip_tail)(struct intel_overlay *); 187e3adcf8fSFrançois Tigeot }; 188e3adcf8fSFrançois Tigeot 189*e3440f96SFrançois Tigeot static struct overlay_registers __iomem * 190e3adcf8fSFrançois Tigeot intel_overlay_map_regs(struct intel_overlay *overlay) 191e3adcf8fSFrançois Tigeot { 192*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 193e3adcf8fSFrançois Tigeot 194*e3440f96SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 195*e3440f96SFrançois Tigeot regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr; 196*e3440f96SFrançois Tigeot else 197e3adcf8fSFrançois Tigeot regs = pmap_mapdev_attr(overlay->dev->agp->base + 198e3adcf8fSFrançois Tigeot overlay->reg_bo->gtt_offset, PAGE_SIZE, 199e3adcf8fSFrançois Tigeot PAT_WRITE_COMBINING); 200*e3440f96SFrançois Tigeot 201*e3440f96SFrançois Tigeot return regs; 202e3adcf8fSFrançois Tigeot } 203e3adcf8fSFrançois Tigeot 204e3adcf8fSFrançois Tigeot static void intel_overlay_unmap_regs(struct intel_overlay *overlay, 205*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 206e3adcf8fSFrançois Tigeot { 207e3adcf8fSFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 208e3adcf8fSFrançois Tigeot pmap_unmapdev((vm_offset_t)regs, PAGE_SIZE); 209e3adcf8fSFrançois Tigeot } 210e3adcf8fSFrançois Tigeot 211e3adcf8fSFrançois Tigeot static int intel_overlay_do_wait_request(struct intel_overlay *overlay, 212e3adcf8fSFrançois Tigeot void (*tail)(struct intel_overlay *)) 213e3adcf8fSFrançois Tigeot { 214e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 215e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 216f192107fSFrançois Tigeot struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; 217e3adcf8fSFrançois Tigeot int ret; 218e3adcf8fSFrançois Tigeot 219b030f26bSFrançois Tigeot BUG_ON(overlay->last_flip_req); 220f192107fSFrançois Tigeot ret = i915_add_request(ring, NULL, &overlay->last_flip_req); 221f192107fSFrançois Tigeot if (ret) 222e3adcf8fSFrançois Tigeot return ret; 223f192107fSFrançois Tigeot 224e3adcf8fSFrançois Tigeot overlay->flip_tail = tail; 225f192107fSFrançois Tigeot ret = i915_wait_seqno(ring, overlay->last_flip_req); 226e3adcf8fSFrançois Tigeot if (ret) 227e3adcf8fSFrançois Tigeot return ret; 228686a02f1SFrançois Tigeot i915_gem_retire_requests(dev); 229e3adcf8fSFrançois Tigeot 230e3adcf8fSFrançois Tigeot overlay->last_flip_req = 0; 231e3adcf8fSFrançois Tigeot return 0; 232e3adcf8fSFrançois Tigeot } 233e3adcf8fSFrançois Tigeot 234e3adcf8fSFrançois Tigeot /* overlay needs to be disable in OCMD reg */ 235e3adcf8fSFrançois Tigeot static int intel_overlay_on(struct intel_overlay *overlay) 236e3adcf8fSFrançois Tigeot { 237e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 238e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 239f192107fSFrançois Tigeot struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; 240e3adcf8fSFrançois Tigeot int ret; 241e3adcf8fSFrançois Tigeot 2427cbd1a46SFrançois Tigeot BUG_ON(overlay->active); 243e3adcf8fSFrançois Tigeot overlay->active = 1; 244e3adcf8fSFrançois Tigeot 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 251f192107fSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON); 252f192107fSFrançois Tigeot intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE); 253f192107fSFrançois Tigeot intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 254f192107fSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 255f192107fSFrançois Tigeot intel_ring_advance(ring); 256f192107fSFrançois Tigeot 257f192107fSFrançois Tigeot return intel_overlay_do_wait_request(overlay, NULL); 258e3adcf8fSFrançois Tigeot } 259e3adcf8fSFrançois Tigeot 260e3adcf8fSFrançois Tigeot /* overlay needs to be enabled in OCMD reg */ 261e3adcf8fSFrançois Tigeot static int intel_overlay_continue(struct intel_overlay *overlay, 262e3adcf8fSFrançois Tigeot bool load_polyphase_filter) 263e3adcf8fSFrançois Tigeot { 264e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 265e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 266f192107fSFrançois Tigeot struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; 267e3adcf8fSFrançois Tigeot u32 flip_addr = overlay->flip_addr; 268e3adcf8fSFrançois Tigeot u32 tmp; 269e3adcf8fSFrançois Tigeot int ret; 270e3adcf8fSFrançois Tigeot 271f192107fSFrançois Tigeot BUG_ON(!overlay->active); 272e3adcf8fSFrançois Tigeot 273e3adcf8fSFrançois Tigeot if (load_polyphase_filter) 274e3adcf8fSFrançois Tigeot flip_addr |= OFC_UPDATE; 275e3adcf8fSFrançois Tigeot 276e3adcf8fSFrançois Tigeot /* check for underruns */ 277e3adcf8fSFrançois Tigeot tmp = I915_READ(DOVSTA); 278e3adcf8fSFrançois Tigeot if (tmp & (1 << 17)) 279e3adcf8fSFrançois Tigeot DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); 280e3adcf8fSFrançois Tigeot 281f192107fSFrançois Tigeot ret = intel_ring_begin(ring, 2); 282f192107fSFrançois Tigeot if (ret) 283e3adcf8fSFrançois Tigeot return ret; 284e3adcf8fSFrançois Tigeot 285f192107fSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 286f192107fSFrançois Tigeot intel_ring_emit(ring, flip_addr); 287f192107fSFrançois Tigeot intel_ring_advance(ring); 288e3adcf8fSFrançois Tigeot 289f192107fSFrançois Tigeot return i915_add_request(ring, NULL, &overlay->last_flip_req); 290e3adcf8fSFrançois Tigeot } 291e3adcf8fSFrançois Tigeot 292e3adcf8fSFrançois Tigeot static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) 293e3adcf8fSFrançois Tigeot { 294e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj = overlay->old_vid_bo; 295e3adcf8fSFrançois Tigeot 296e3adcf8fSFrançois Tigeot i915_gem_object_unpin(obj); 297e3adcf8fSFrançois Tigeot drm_gem_object_unreference(&obj->base); 298e3adcf8fSFrançois Tigeot 299e3adcf8fSFrançois Tigeot overlay->old_vid_bo = NULL; 300e3adcf8fSFrançois Tigeot } 301e3adcf8fSFrançois Tigeot 302e3adcf8fSFrançois Tigeot static void intel_overlay_off_tail(struct intel_overlay *overlay) 303e3adcf8fSFrançois Tigeot { 304e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj = overlay->vid_bo; 305e3adcf8fSFrançois Tigeot 306e3adcf8fSFrançois Tigeot /* never have the overlay hw on without showing a frame */ 307*e3440f96SFrançois Tigeot BUG_ON(!overlay->vid_bo); 308e3adcf8fSFrançois Tigeot 309e3adcf8fSFrançois Tigeot i915_gem_object_unpin(obj); 310e3adcf8fSFrançois Tigeot drm_gem_object_unreference(&obj->base); 311e3adcf8fSFrançois Tigeot overlay->vid_bo = NULL; 312e3adcf8fSFrançois Tigeot 313e3adcf8fSFrançois Tigeot overlay->crtc->overlay = NULL; 314e3adcf8fSFrançois Tigeot overlay->crtc = NULL; 315e3adcf8fSFrançois Tigeot overlay->active = 0; 316e3adcf8fSFrançois Tigeot } 317e3adcf8fSFrançois Tigeot 318e3adcf8fSFrançois Tigeot /* overlay needs to be disabled in OCMD reg */ 319e3adcf8fSFrançois Tigeot static int intel_overlay_off(struct intel_overlay *overlay) 320e3adcf8fSFrançois Tigeot { 321e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 322e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 323f192107fSFrançois Tigeot struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; 324e3adcf8fSFrançois Tigeot u32 flip_addr = overlay->flip_addr; 325e3adcf8fSFrançois Tigeot int ret; 326e3adcf8fSFrançois Tigeot 327f192107fSFrançois Tigeot BUG_ON(!overlay->active); 328e3adcf8fSFrançois Tigeot 329e3adcf8fSFrançois Tigeot /* According to intel docs the overlay hw may hang (when switching 330e3adcf8fSFrançois Tigeot * off) without loading the filter coeffs. It is however unclear whether 331e3adcf8fSFrançois Tigeot * this applies to the disabling of the overlay or to the switching off 332e3adcf8fSFrançois Tigeot * of the hw. Do it in both cases */ 333e3adcf8fSFrançois Tigeot flip_addr |= OFC_UPDATE; 334e3adcf8fSFrançois Tigeot 335f192107fSFrançois Tigeot ret = intel_ring_begin(ring, 6); 336f192107fSFrançois Tigeot if (ret) 337e3adcf8fSFrançois Tigeot return ret; 338e3adcf8fSFrançois Tigeot 339f192107fSFrançois Tigeot /* wait for overlay to go idle */ 340f192107fSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 341f192107fSFrançois Tigeot intel_ring_emit(ring, flip_addr); 342f192107fSFrançois Tigeot intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 343f192107fSFrançois Tigeot /* turn overlay off */ 34419df918dSFrançois Tigeot if (IS_I830(dev)) { 34519df918dSFrançois Tigeot /* Workaround: Don't disable the overlay fully, since otherwise 34619df918dSFrançois Tigeot * it dies on the next OVERLAY_ON cmd. */ 34719df918dSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 34819df918dSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 34919df918dSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 35019df918dSFrançois Tigeot } else { 351f192107fSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF); 352f192107fSFrançois Tigeot intel_ring_emit(ring, flip_addr); 353f192107fSFrançois Tigeot intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 35419df918dSFrançois Tigeot } 355f192107fSFrançois Tigeot intel_ring_advance(ring); 356f192107fSFrançois Tigeot 357f192107fSFrançois Tigeot return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail); 358e3adcf8fSFrançois Tigeot } 359e3adcf8fSFrançois Tigeot 360e3adcf8fSFrançois Tigeot /* recover from an interruption due to a signal 361e3adcf8fSFrançois Tigeot * We have to be careful not to repeat work forever an make forward progess. */ 362e3adcf8fSFrançois Tigeot static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) 363e3adcf8fSFrançois Tigeot { 364e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 365e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 366b030f26bSFrançois Tigeot struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; 367e3adcf8fSFrançois Tigeot int ret; 368e3adcf8fSFrançois Tigeot 369e3adcf8fSFrançois Tigeot if (overlay->last_flip_req == 0) 370e3adcf8fSFrançois Tigeot return 0; 371e3adcf8fSFrançois Tigeot 372b030f26bSFrançois Tigeot ret = i915_wait_seqno(ring, overlay->last_flip_req); 373e3adcf8fSFrançois Tigeot if (ret) 374e3adcf8fSFrançois Tigeot return ret; 375b030f26bSFrançois Tigeot i915_gem_retire_requests(dev); 376e3adcf8fSFrançois Tigeot 377e3adcf8fSFrançois Tigeot if (overlay->flip_tail) 378e3adcf8fSFrançois Tigeot overlay->flip_tail(overlay); 379e3adcf8fSFrançois Tigeot 380e3adcf8fSFrançois Tigeot overlay->last_flip_req = 0; 381e3adcf8fSFrançois Tigeot return 0; 382e3adcf8fSFrançois Tigeot } 383e3adcf8fSFrançois Tigeot 384e3adcf8fSFrançois Tigeot /* Wait for pending overlay flip and release old frame. 385e3adcf8fSFrançois Tigeot * Needs to be called before the overlay register are changed 386e3adcf8fSFrançois Tigeot * via intel_overlay_(un)map_regs 387e3adcf8fSFrançois Tigeot */ 388e3adcf8fSFrançois Tigeot static int intel_overlay_release_old_vid(struct intel_overlay *overlay) 389e3adcf8fSFrançois Tigeot { 390e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 391e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 392f192107fSFrançois Tigeot struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; 393e3adcf8fSFrançois Tigeot int ret; 394e3adcf8fSFrançois Tigeot 395e3adcf8fSFrançois Tigeot /* Only wait if there is actually an old frame to release to 396e3adcf8fSFrançois Tigeot * guarantee forward progress. 397e3adcf8fSFrançois Tigeot */ 398e3adcf8fSFrançois Tigeot if (!overlay->old_vid_bo) 399e3adcf8fSFrançois Tigeot return 0; 400e3adcf8fSFrançois Tigeot 401e3adcf8fSFrançois Tigeot if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { 402e3adcf8fSFrançois Tigeot /* synchronous slowpath */ 403f192107fSFrançois Tigeot ret = intel_ring_begin(ring, 2); 404f192107fSFrançois Tigeot if (ret) 405e3adcf8fSFrançois Tigeot return ret; 406e3adcf8fSFrançois Tigeot 407f192107fSFrançois Tigeot intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 408f192107fSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 409f192107fSFrançois Tigeot intel_ring_advance(ring); 410e3adcf8fSFrançois Tigeot 411f192107fSFrançois Tigeot ret = intel_overlay_do_wait_request(overlay, 412e3adcf8fSFrançois Tigeot intel_overlay_release_old_vid_tail); 413e3adcf8fSFrançois Tigeot if (ret) 414e3adcf8fSFrançois Tigeot return ret; 415e3adcf8fSFrançois Tigeot } 416e3adcf8fSFrançois Tigeot 417e3adcf8fSFrançois Tigeot intel_overlay_release_old_vid_tail(overlay); 418e3adcf8fSFrançois Tigeot return 0; 419e3adcf8fSFrançois Tigeot } 420e3adcf8fSFrançois Tigeot 421e3adcf8fSFrançois Tigeot struct put_image_params { 422e3adcf8fSFrançois Tigeot int format; 423e3adcf8fSFrançois Tigeot short dst_x; 424e3adcf8fSFrançois Tigeot short dst_y; 425e3adcf8fSFrançois Tigeot short dst_w; 426e3adcf8fSFrançois Tigeot short dst_h; 427e3adcf8fSFrançois Tigeot short src_w; 428e3adcf8fSFrançois Tigeot short src_scan_h; 429e3adcf8fSFrançois Tigeot short src_scan_w; 430e3adcf8fSFrançois Tigeot short src_h; 431e3adcf8fSFrançois Tigeot short stride_Y; 432e3adcf8fSFrançois Tigeot short stride_UV; 433e3adcf8fSFrançois Tigeot int offset_Y; 434e3adcf8fSFrançois Tigeot int offset_U; 435e3adcf8fSFrançois Tigeot int offset_V; 436e3adcf8fSFrançois Tigeot }; 437e3adcf8fSFrançois Tigeot 438e3adcf8fSFrançois Tigeot static int packed_depth_bytes(u32 format) 439e3adcf8fSFrançois Tigeot { 440e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 441e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 442e3adcf8fSFrançois Tigeot return 4; 443e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 444e3adcf8fSFrançois Tigeot /* return 6; not implemented */ 445e3adcf8fSFrançois Tigeot default: 446e3adcf8fSFrançois Tigeot return -EINVAL; 447e3adcf8fSFrançois Tigeot } 448e3adcf8fSFrançois Tigeot } 449e3adcf8fSFrançois Tigeot 450e3adcf8fSFrançois Tigeot static int packed_width_bytes(u32 format, short width) 451e3adcf8fSFrançois Tigeot { 452e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 453e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 454e3adcf8fSFrançois Tigeot return width << 1; 455e3adcf8fSFrançois Tigeot default: 456e3adcf8fSFrançois Tigeot return -EINVAL; 457e3adcf8fSFrançois Tigeot } 458e3adcf8fSFrançois Tigeot } 459e3adcf8fSFrançois Tigeot 460e3adcf8fSFrançois Tigeot static int uv_hsubsampling(u32 format) 461e3adcf8fSFrançois Tigeot { 462e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 463e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 464e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 465e3adcf8fSFrançois Tigeot return 2; 466e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 467e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 468e3adcf8fSFrançois Tigeot return 4; 469e3adcf8fSFrançois Tigeot default: 470e3adcf8fSFrançois Tigeot return -EINVAL; 471e3adcf8fSFrançois Tigeot } 472e3adcf8fSFrançois Tigeot } 473e3adcf8fSFrançois Tigeot 474e3adcf8fSFrançois Tigeot static int uv_vsubsampling(u32 format) 475e3adcf8fSFrançois Tigeot { 476e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 477e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 478e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 479e3adcf8fSFrançois Tigeot return 2; 480e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 481e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 482e3adcf8fSFrançois Tigeot return 1; 483e3adcf8fSFrançois Tigeot default: 484e3adcf8fSFrançois Tigeot return -EINVAL; 485e3adcf8fSFrançois Tigeot } 486e3adcf8fSFrançois Tigeot } 487e3adcf8fSFrançois Tigeot 488e3adcf8fSFrançois Tigeot static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) 489e3adcf8fSFrançois Tigeot { 490e3adcf8fSFrançois Tigeot u32 mask, shift, ret; 491e3adcf8fSFrançois Tigeot if (IS_GEN2(dev)) { 492e3adcf8fSFrançois Tigeot mask = 0x1f; 493e3adcf8fSFrançois Tigeot shift = 5; 494e3adcf8fSFrançois Tigeot } else { 495e3adcf8fSFrançois Tigeot mask = 0x3f; 496e3adcf8fSFrançois Tigeot shift = 6; 497e3adcf8fSFrançois Tigeot } 498e3adcf8fSFrançois Tigeot ret = ((offset + width + mask) >> shift) - (offset >> shift); 499e3adcf8fSFrançois Tigeot if (!IS_GEN2(dev)) 500e3adcf8fSFrançois Tigeot ret <<= 1; 501e3adcf8fSFrançois Tigeot ret -= 1; 502e3adcf8fSFrançois Tigeot return ret << 2; 503e3adcf8fSFrançois Tigeot } 504e3adcf8fSFrançois Tigeot 505e3adcf8fSFrançois Tigeot static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { 506e3adcf8fSFrançois Tigeot 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0, 507e3adcf8fSFrançois Tigeot 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440, 508e3adcf8fSFrançois Tigeot 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0, 509e3adcf8fSFrançois Tigeot 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380, 510e3adcf8fSFrançois Tigeot 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320, 511e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0, 512e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260, 513e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200, 514e3adcf8fSFrançois Tigeot 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0, 515e3adcf8fSFrançois Tigeot 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160, 516e3adcf8fSFrançois Tigeot 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120, 517e3adcf8fSFrançois Tigeot 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0, 518e3adcf8fSFrançois Tigeot 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0, 519e3adcf8fSFrançois Tigeot 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, 520e3adcf8fSFrançois Tigeot 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, 521e3adcf8fSFrançois Tigeot 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, 522e3adcf8fSFrançois Tigeot 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 523e3adcf8fSFrançois Tigeot }; 524e3adcf8fSFrançois Tigeot 525e3adcf8fSFrançois Tigeot static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { 526e3adcf8fSFrançois Tigeot 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, 527e3adcf8fSFrançois Tigeot 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, 528e3adcf8fSFrançois Tigeot 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880, 529e3adcf8fSFrançois Tigeot 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00, 530e3adcf8fSFrançois Tigeot 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0, 531e3adcf8fSFrançois Tigeot 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, 532e3adcf8fSFrançois Tigeot 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, 533e3adcf8fSFrançois Tigeot 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, 534e3adcf8fSFrançois Tigeot 0x3000, 0x0800, 0x3000 535e3adcf8fSFrançois Tigeot }; 536e3adcf8fSFrançois Tigeot 537*e3440f96SFrançois Tigeot static void update_polyphase_filter(struct overlay_registers __iomem *regs) 538e3adcf8fSFrançois Tigeot { 539*e3440f96SFrançois Tigeot memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs)); 540*e3440f96SFrançois Tigeot memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs, 541*e3440f96SFrançois Tigeot sizeof(uv_static_hcoeffs)); 542e3adcf8fSFrançois Tigeot } 543e3adcf8fSFrançois Tigeot 544e3adcf8fSFrançois Tigeot static bool update_scaling_factors(struct intel_overlay *overlay, 545*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs, 546e3adcf8fSFrançois Tigeot struct put_image_params *params) 547e3adcf8fSFrançois Tigeot { 548e3adcf8fSFrançois Tigeot /* fixed point with a 12 bit shift */ 549e3adcf8fSFrançois Tigeot u32 xscale, yscale, xscale_UV, yscale_UV; 550e3adcf8fSFrançois Tigeot #define FP_SHIFT 12 551e3adcf8fSFrançois Tigeot #define FRACT_MASK 0xfff 552e3adcf8fSFrançois Tigeot bool scale_changed = false; 553e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(params->format); 554e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(params->format); 555e3adcf8fSFrançois Tigeot 556e3adcf8fSFrançois Tigeot if (params->dst_w > 1) 557e3adcf8fSFrançois Tigeot xscale = ((params->src_scan_w - 1) << FP_SHIFT) 558e3adcf8fSFrançois Tigeot /(params->dst_w); 559e3adcf8fSFrançois Tigeot else 560e3adcf8fSFrançois Tigeot xscale = 1 << FP_SHIFT; 561e3adcf8fSFrançois Tigeot 562e3adcf8fSFrançois Tigeot if (params->dst_h > 1) 563e3adcf8fSFrançois Tigeot yscale = ((params->src_scan_h - 1) << FP_SHIFT) 564e3adcf8fSFrançois Tigeot /(params->dst_h); 565e3adcf8fSFrançois Tigeot else 566e3adcf8fSFrançois Tigeot yscale = 1 << FP_SHIFT; 567e3adcf8fSFrançois Tigeot 568e3adcf8fSFrançois Tigeot /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ 569e3adcf8fSFrançois Tigeot xscale_UV = xscale/uv_hscale; 570e3adcf8fSFrançois Tigeot yscale_UV = yscale/uv_vscale; 571e3adcf8fSFrançois Tigeot /* make the Y scale to UV scale ratio an exact multiply */ 572e3adcf8fSFrançois Tigeot xscale = xscale_UV * uv_hscale; 573e3adcf8fSFrançois Tigeot yscale = yscale_UV * uv_vscale; 574e3adcf8fSFrançois Tigeot /*} else { 575e3adcf8fSFrançois Tigeot xscale_UV = 0; 576e3adcf8fSFrançois Tigeot yscale_UV = 0; 577e3adcf8fSFrançois Tigeot }*/ 578e3adcf8fSFrançois Tigeot 579e3adcf8fSFrançois Tigeot if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) 580e3adcf8fSFrançois Tigeot scale_changed = true; 581e3adcf8fSFrançois Tigeot overlay->old_xscale = xscale; 582e3adcf8fSFrançois Tigeot overlay->old_yscale = yscale; 583e3adcf8fSFrançois Tigeot 584*e3440f96SFrançois Tigeot iowrite32(((yscale & FRACT_MASK) << 20) | 585e3adcf8fSFrançois Tigeot ((xscale >> FP_SHIFT) << 16) | 586*e3440f96SFrançois Tigeot ((xscale & FRACT_MASK) << 3), 587*e3440f96SFrançois Tigeot ®s->YRGBSCALE); 588e3adcf8fSFrançois Tigeot 589*e3440f96SFrançois Tigeot iowrite32(((yscale_UV & FRACT_MASK) << 20) | 590e3adcf8fSFrançois Tigeot ((xscale_UV >> FP_SHIFT) << 16) | 591*e3440f96SFrançois Tigeot ((xscale_UV & FRACT_MASK) << 3), 592*e3440f96SFrançois Tigeot ®s->UVSCALE); 593e3adcf8fSFrançois Tigeot 594*e3440f96SFrançois Tigeot iowrite32((((yscale >> FP_SHIFT) << 16) | 595*e3440f96SFrançois Tigeot ((yscale_UV >> FP_SHIFT) << 0)), 596*e3440f96SFrançois Tigeot ®s->UVSCALEV); 597e3adcf8fSFrançois Tigeot 598e3adcf8fSFrançois Tigeot if (scale_changed) 599e3adcf8fSFrançois Tigeot update_polyphase_filter(regs); 600e3adcf8fSFrançois Tigeot 601e3adcf8fSFrançois Tigeot return scale_changed; 602e3adcf8fSFrançois Tigeot } 603e3adcf8fSFrançois Tigeot 604e3adcf8fSFrançois Tigeot static void update_colorkey(struct intel_overlay *overlay, 605*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 606e3adcf8fSFrançois Tigeot { 607e3adcf8fSFrançois Tigeot u32 key = overlay->color_key; 608e3adcf8fSFrançois Tigeot 609e3adcf8fSFrançois Tigeot switch (overlay->crtc->base.fb->bits_per_pixel) { 610e3adcf8fSFrançois Tigeot case 8: 611*e3440f96SFrançois Tigeot iowrite32(0, ®s->DCLRKV); 612*e3440f96SFrançois Tigeot iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, ®s->DCLRKM); 613e3adcf8fSFrançois Tigeot break; 614e3adcf8fSFrançois Tigeot 615e3adcf8fSFrançois Tigeot case 16: 616e3adcf8fSFrançois Tigeot if (overlay->crtc->base.fb->depth == 15) { 617*e3440f96SFrançois Tigeot iowrite32(RGB15_TO_COLORKEY(key), ®s->DCLRKV); 618*e3440f96SFrançois Tigeot iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE, 619*e3440f96SFrançois Tigeot ®s->DCLRKM); 620e3adcf8fSFrançois Tigeot } else { 621*e3440f96SFrançois Tigeot iowrite32(RGB16_TO_COLORKEY(key), ®s->DCLRKV); 622*e3440f96SFrançois Tigeot iowrite32(CLK_RGB16_MASK | DST_KEY_ENABLE, 623*e3440f96SFrançois Tigeot ®s->DCLRKM); 624e3adcf8fSFrançois Tigeot } 625e3adcf8fSFrançois Tigeot break; 626e3adcf8fSFrançois Tigeot 627e3adcf8fSFrançois Tigeot case 24: 628e3adcf8fSFrançois Tigeot case 32: 629*e3440f96SFrançois Tigeot iowrite32(key, ®s->DCLRKV); 630*e3440f96SFrançois Tigeot iowrite32(CLK_RGB24_MASK | DST_KEY_ENABLE, ®s->DCLRKM); 631e3adcf8fSFrançois Tigeot break; 632e3adcf8fSFrançois Tigeot } 633e3adcf8fSFrançois Tigeot } 634e3adcf8fSFrançois Tigeot 635e3adcf8fSFrançois Tigeot static u32 overlay_cmd_reg(struct put_image_params *params) 636e3adcf8fSFrançois Tigeot { 637e3adcf8fSFrançois Tigeot u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0; 638e3adcf8fSFrançois Tigeot 639e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PLANAR) { 640e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_DEPTH_MASK) { 641e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 642e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_422_PLANAR; 643e3adcf8fSFrançois Tigeot break; 644e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 645e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_420_PLANAR; 646e3adcf8fSFrançois Tigeot break; 647e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 648e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 649e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_410_PLANAR; 650e3adcf8fSFrançois Tigeot break; 651e3adcf8fSFrançois Tigeot } 652e3adcf8fSFrançois Tigeot } else { /* YUV packed */ 653e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_DEPTH_MASK) { 654e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 655e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_422_PACKED; 656e3adcf8fSFrançois Tigeot break; 657e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 658e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_411_PACKED; 659e3adcf8fSFrançois Tigeot break; 660e3adcf8fSFrançois Tigeot } 661e3adcf8fSFrançois Tigeot 662e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_SWAP_MASK) { 663e3adcf8fSFrançois Tigeot case I915_OVERLAY_NO_SWAP: 664e3adcf8fSFrançois Tigeot break; 665e3adcf8fSFrançois Tigeot case I915_OVERLAY_UV_SWAP: 666e3adcf8fSFrançois Tigeot cmd |= OCMD_UV_SWAP; 667e3adcf8fSFrançois Tigeot break; 668e3adcf8fSFrançois Tigeot case I915_OVERLAY_Y_SWAP: 669e3adcf8fSFrançois Tigeot cmd |= OCMD_Y_SWAP; 670e3adcf8fSFrançois Tigeot break; 671e3adcf8fSFrançois Tigeot case I915_OVERLAY_Y_AND_UV_SWAP: 672e3adcf8fSFrançois Tigeot cmd |= OCMD_Y_AND_UV_SWAP; 673e3adcf8fSFrançois Tigeot break; 674e3adcf8fSFrançois Tigeot } 675e3adcf8fSFrançois Tigeot } 676e3adcf8fSFrançois Tigeot 677e3adcf8fSFrançois Tigeot return cmd; 678e3adcf8fSFrançois Tigeot } 679e3adcf8fSFrançois Tigeot 680e3adcf8fSFrançois Tigeot static int intel_overlay_do_put_image(struct intel_overlay *overlay, 681e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo, 682e3adcf8fSFrançois Tigeot struct put_image_params *params) 683e3adcf8fSFrançois Tigeot { 684e3adcf8fSFrançois Tigeot int ret, tmp_width; 685*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 686e3adcf8fSFrançois Tigeot bool scale_changed = false; 687*e3440f96SFrançois Tigeot struct drm_device *dev = overlay->dev; 688*e3440f96SFrançois Tigeot u32 swidth, swidthsw, sheight, ostride; 689e3adcf8fSFrançois Tigeot 690*e3440f96SFrançois Tigeot BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 691*e3440f96SFrançois Tigeot BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); 692*e3440f96SFrançois Tigeot BUG_ON(!overlay); 693e3adcf8fSFrançois Tigeot 694e3adcf8fSFrançois Tigeot ret = intel_overlay_release_old_vid(overlay); 695e3adcf8fSFrançois Tigeot if (ret != 0) 696e3adcf8fSFrançois Tigeot return ret; 697e3adcf8fSFrançois Tigeot 698e3adcf8fSFrançois Tigeot ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL); 699e3adcf8fSFrançois Tigeot if (ret != 0) 700*e3440f96SFrançois Tigeot return ret; 701e3adcf8fSFrançois Tigeot 702e3adcf8fSFrançois Tigeot ret = i915_gem_object_put_fence(new_bo); 703e3adcf8fSFrançois Tigeot if (ret) 704e3adcf8fSFrançois Tigeot goto out_unpin; 705e3adcf8fSFrançois Tigeot 706e3adcf8fSFrançois Tigeot if (!overlay->active) { 707*e3440f96SFrançois Tigeot u32 oconfig; 708e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 709e3adcf8fSFrançois Tigeot if (!regs) { 710e3adcf8fSFrançois Tigeot ret = -ENOMEM; 711e3adcf8fSFrançois Tigeot goto out_unpin; 712e3adcf8fSFrançois Tigeot } 713*e3440f96SFrançois Tigeot oconfig = OCONF_CC_OUT_8BIT; 714e3adcf8fSFrançois Tigeot if (IS_GEN4(overlay->dev)) 715*e3440f96SFrançois Tigeot oconfig |= OCONF_CSC_MODE_BT709; 716*e3440f96SFrançois Tigeot oconfig |= overlay->crtc->pipe == 0 ? 717e3adcf8fSFrançois Tigeot OCONF_PIPE_A : OCONF_PIPE_B; 718*e3440f96SFrançois Tigeot iowrite32(oconfig, ®s->OCONFIG); 719e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 720e3adcf8fSFrançois Tigeot 721e3adcf8fSFrançois Tigeot ret = intel_overlay_on(overlay); 722e3adcf8fSFrançois Tigeot if (ret != 0) 723e3adcf8fSFrançois Tigeot goto out_unpin; 724e3adcf8fSFrançois Tigeot } 725e3adcf8fSFrançois Tigeot 726e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 727e3adcf8fSFrançois Tigeot if (!regs) { 728e3adcf8fSFrançois Tigeot ret = -ENOMEM; 729e3adcf8fSFrançois Tigeot goto out_unpin; 730e3adcf8fSFrançois Tigeot } 731e3adcf8fSFrançois Tigeot 732*e3440f96SFrançois Tigeot iowrite32((params->dst_y << 16) | params->dst_x, ®s->DWINPOS); 733*e3440f96SFrançois Tigeot iowrite32((params->dst_h << 16) | params->dst_w, ®s->DWINSZ); 734e3adcf8fSFrançois Tigeot 735e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PACKED) 736e3adcf8fSFrançois Tigeot tmp_width = packed_width_bytes(params->format, params->src_w); 737e3adcf8fSFrançois Tigeot else 738e3adcf8fSFrançois Tigeot tmp_width = params->src_w; 739e3adcf8fSFrançois Tigeot 740*e3440f96SFrançois Tigeot swidth = params->src_w; 741*e3440f96SFrançois Tigeot swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width); 742*e3440f96SFrançois Tigeot sheight = params->src_h; 743*e3440f96SFrançois Tigeot iowrite32(new_bo->gtt_offset + params->offset_Y, ®s->OBUF_0Y); 744*e3440f96SFrançois Tigeot ostride = params->stride_Y; 745e3adcf8fSFrançois Tigeot 746e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PLANAR) { 747e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(params->format); 748e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(params->format); 749e3adcf8fSFrançois Tigeot u32 tmp_U, tmp_V; 750*e3440f96SFrançois Tigeot swidth |= (params->src_w/uv_hscale) << 16; 751e3adcf8fSFrançois Tigeot tmp_U = calc_swidthsw(overlay->dev, params->offset_U, 752e3adcf8fSFrançois Tigeot params->src_w/uv_hscale); 753e3adcf8fSFrançois Tigeot tmp_V = calc_swidthsw(overlay->dev, params->offset_V, 754e3adcf8fSFrançois Tigeot params->src_w/uv_hscale); 755*e3440f96SFrançois Tigeot swidthsw |= max_t(u32, tmp_U, tmp_V) << 16; 756*e3440f96SFrançois Tigeot sheight |= (params->src_h/uv_vscale) << 16; 757*e3440f96SFrançois Tigeot iowrite32(new_bo->gtt_offset + params->offset_U, ®s->OBUF_0U); 758*e3440f96SFrançois Tigeot iowrite32(new_bo->gtt_offset + params->offset_V, ®s->OBUF_0V); 759*e3440f96SFrançois Tigeot ostride |= params->stride_UV << 16; 760e3adcf8fSFrançois Tigeot } 761e3adcf8fSFrançois Tigeot 762*e3440f96SFrançois Tigeot iowrite32(swidth, ®s->SWIDTH); 763*e3440f96SFrançois Tigeot iowrite32(swidthsw, ®s->SWIDTHSW); 764*e3440f96SFrançois Tigeot iowrite32(sheight, ®s->SHEIGHT); 765*e3440f96SFrançois Tigeot iowrite32(ostride, ®s->OSTRIDE); 766*e3440f96SFrançois Tigeot 767e3adcf8fSFrançois Tigeot scale_changed = update_scaling_factors(overlay, regs, params); 768e3adcf8fSFrançois Tigeot 769e3adcf8fSFrançois Tigeot update_colorkey(overlay, regs); 770e3adcf8fSFrançois Tigeot 771*e3440f96SFrançois Tigeot iowrite32(overlay_cmd_reg(params), ®s->OCMD); 772e3adcf8fSFrançois Tigeot 773e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 774e3adcf8fSFrançois Tigeot 775e3adcf8fSFrançois Tigeot ret = intel_overlay_continue(overlay, scale_changed); 776e3adcf8fSFrançois Tigeot if (ret) 777e3adcf8fSFrançois Tigeot goto out_unpin; 778e3adcf8fSFrançois Tigeot 779e3adcf8fSFrançois Tigeot overlay->old_vid_bo = overlay->vid_bo; 780e3adcf8fSFrançois Tigeot overlay->vid_bo = new_bo; 781e3adcf8fSFrançois Tigeot 782e3adcf8fSFrançois Tigeot return 0; 783e3adcf8fSFrançois Tigeot 784e3adcf8fSFrançois Tigeot out_unpin: 785e3adcf8fSFrançois Tigeot i915_gem_object_unpin(new_bo); 786e3adcf8fSFrançois Tigeot return ret; 787e3adcf8fSFrançois Tigeot } 788e3adcf8fSFrançois Tigeot 789e3adcf8fSFrançois Tigeot int intel_overlay_switch_off(struct intel_overlay *overlay) 790e3adcf8fSFrançois Tigeot { 791*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 792*e3440f96SFrançois Tigeot struct drm_device *dev = overlay->dev; 793e3adcf8fSFrançois Tigeot int ret; 794e3adcf8fSFrançois Tigeot 795*e3440f96SFrançois Tigeot BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 796*e3440f96SFrançois Tigeot BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); 797e3adcf8fSFrançois Tigeot 798e3adcf8fSFrançois Tigeot ret = intel_overlay_recover_from_interrupt(overlay); 799e3adcf8fSFrançois Tigeot if (ret != 0) 800e3adcf8fSFrançois Tigeot return ret; 801e3adcf8fSFrançois Tigeot 802e3adcf8fSFrançois Tigeot if (!overlay->active) 803e3adcf8fSFrançois Tigeot return 0; 804e3adcf8fSFrançois Tigeot 805e3adcf8fSFrançois Tigeot ret = intel_overlay_release_old_vid(overlay); 806e3adcf8fSFrançois Tigeot if (ret != 0) 807e3adcf8fSFrançois Tigeot return ret; 808e3adcf8fSFrançois Tigeot 809e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 810*e3440f96SFrançois Tigeot iowrite32(0, ®s->OCMD); 811e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 812e3adcf8fSFrançois Tigeot 813e3adcf8fSFrançois Tigeot ret = intel_overlay_off(overlay); 814e3adcf8fSFrançois Tigeot if (ret != 0) 815e3adcf8fSFrançois Tigeot return ret; 816e3adcf8fSFrançois Tigeot 817e3adcf8fSFrançois Tigeot intel_overlay_off_tail(overlay); 818e3adcf8fSFrançois Tigeot return 0; 819e3adcf8fSFrançois Tigeot } 820e3adcf8fSFrançois Tigeot 821e3adcf8fSFrançois Tigeot static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, 822e3adcf8fSFrançois Tigeot struct intel_crtc *crtc) 823e3adcf8fSFrançois Tigeot { 824e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = overlay->dev->dev_private; 825e3adcf8fSFrançois Tigeot 826e3adcf8fSFrançois Tigeot if (!crtc->active) 827e3adcf8fSFrançois Tigeot return -EINVAL; 828e3adcf8fSFrançois Tigeot 829e3adcf8fSFrançois Tigeot /* can't use the overlay with double wide pipe */ 830e3adcf8fSFrançois Tigeot if (INTEL_INFO(overlay->dev)->gen < 4 && 831e3adcf8fSFrançois Tigeot (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) 832e3adcf8fSFrançois Tigeot return -EINVAL; 833e3adcf8fSFrançois Tigeot 834e3adcf8fSFrançois Tigeot return 0; 835e3adcf8fSFrançois Tigeot } 836e3adcf8fSFrançois Tigeot 837e3adcf8fSFrançois Tigeot static void update_pfit_vscale_ratio(struct intel_overlay *overlay) 838e3adcf8fSFrançois Tigeot { 839e3adcf8fSFrançois Tigeot struct drm_device *dev = overlay->dev; 840e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 841e3adcf8fSFrançois Tigeot u32 pfit_control = I915_READ(PFIT_CONTROL); 842e3adcf8fSFrançois Tigeot u32 ratio; 843e3adcf8fSFrançois Tigeot 844e3adcf8fSFrançois Tigeot /* XXX: This is not the same logic as in the xorg driver, but more in 845e3adcf8fSFrançois Tigeot * line with the intel documentation for the i965 846e3adcf8fSFrançois Tigeot */ 847e3adcf8fSFrançois Tigeot if (INTEL_INFO(dev)->gen >= 4) { 848e3adcf8fSFrançois Tigeot /* on i965 use the PGM reg to read out the autoscaler values */ 849e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; 850e3adcf8fSFrançois Tigeot } else { 851e3adcf8fSFrançois Tigeot if (pfit_control & VERT_AUTO_SCALE) 852e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_AUTO_RATIOS); 853e3adcf8fSFrançois Tigeot else 854e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_PGM_RATIOS); 855e3adcf8fSFrançois Tigeot ratio >>= PFIT_VERT_SCALE_SHIFT; 856e3adcf8fSFrançois Tigeot } 857e3adcf8fSFrançois Tigeot 858e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio = ratio; 859e3adcf8fSFrançois Tigeot } 860e3adcf8fSFrançois Tigeot 861e3adcf8fSFrançois Tigeot static int check_overlay_dst(struct intel_overlay *overlay, 862e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *rec) 863e3adcf8fSFrançois Tigeot { 864e3adcf8fSFrançois Tigeot struct drm_display_mode *mode = &overlay->crtc->base.mode; 865e3adcf8fSFrançois Tigeot 866e3adcf8fSFrançois Tigeot if (rec->dst_x < mode->hdisplay && 867e3adcf8fSFrançois Tigeot rec->dst_x + rec->dst_width <= mode->hdisplay && 868e3adcf8fSFrançois Tigeot rec->dst_y < mode->vdisplay && 869e3adcf8fSFrançois Tigeot rec->dst_y + rec->dst_height <= mode->vdisplay) 870e3adcf8fSFrançois Tigeot return 0; 871e3adcf8fSFrançois Tigeot else 872e3adcf8fSFrançois Tigeot return -EINVAL; 873e3adcf8fSFrançois Tigeot } 874e3adcf8fSFrançois Tigeot 875e3adcf8fSFrançois Tigeot static int check_overlay_scaling(struct put_image_params *rec) 876e3adcf8fSFrançois Tigeot { 877e3adcf8fSFrançois Tigeot u32 tmp; 878e3adcf8fSFrançois Tigeot 879e3adcf8fSFrançois Tigeot /* downscaling limit is 8.0 */ 880e3adcf8fSFrançois Tigeot tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16; 881e3adcf8fSFrançois Tigeot if (tmp > 7) 882e3adcf8fSFrançois Tigeot return -EINVAL; 883e3adcf8fSFrançois Tigeot tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16; 884e3adcf8fSFrançois Tigeot if (tmp > 7) 885e3adcf8fSFrançois Tigeot return -EINVAL; 886e3adcf8fSFrançois Tigeot 887e3adcf8fSFrançois Tigeot return 0; 888e3adcf8fSFrançois Tigeot } 889e3adcf8fSFrançois Tigeot 890e3adcf8fSFrançois Tigeot static int check_overlay_src(struct drm_device *dev, 891e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *rec, 892e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo) 893e3adcf8fSFrançois Tigeot { 894e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(rec->flags); 895e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(rec->flags); 896e3adcf8fSFrançois Tigeot u32 stride_mask; 897e3adcf8fSFrançois Tigeot int depth; 898e3adcf8fSFrançois Tigeot u32 tmp; 899e3adcf8fSFrançois Tigeot 900e3adcf8fSFrançois Tigeot /* check src dimensions */ 901e3adcf8fSFrançois Tigeot if (IS_845G(dev) || IS_I830(dev)) { 902e3adcf8fSFrançois Tigeot if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || 903e3adcf8fSFrançois Tigeot rec->src_width > IMAGE_MAX_WIDTH_LEGACY) 904e3adcf8fSFrançois Tigeot return -EINVAL; 905e3adcf8fSFrançois Tigeot } else { 906e3adcf8fSFrançois Tigeot if (rec->src_height > IMAGE_MAX_HEIGHT || 907e3adcf8fSFrançois Tigeot rec->src_width > IMAGE_MAX_WIDTH) 908e3adcf8fSFrançois Tigeot return -EINVAL; 909e3adcf8fSFrançois Tigeot } 910e3adcf8fSFrançois Tigeot 911e3adcf8fSFrançois Tigeot /* better safe than sorry, use 4 as the maximal subsampling ratio */ 912e3adcf8fSFrançois Tigeot if (rec->src_height < N_VERT_Y_TAPS*4 || 913e3adcf8fSFrançois Tigeot rec->src_width < N_HORIZ_Y_TAPS*4) 914e3adcf8fSFrançois Tigeot return -EINVAL; 915e3adcf8fSFrançois Tigeot 916e3adcf8fSFrançois Tigeot /* check alignment constraints */ 917e3adcf8fSFrançois Tigeot switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 918e3adcf8fSFrançois Tigeot case I915_OVERLAY_RGB: 919e3adcf8fSFrançois Tigeot /* not implemented */ 920e3adcf8fSFrançois Tigeot return -EINVAL; 921e3adcf8fSFrançois Tigeot 922e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PACKED: 923e3adcf8fSFrançois Tigeot if (uv_vscale != 1) 924e3adcf8fSFrançois Tigeot return -EINVAL; 925e3adcf8fSFrançois Tigeot 926e3adcf8fSFrançois Tigeot depth = packed_depth_bytes(rec->flags); 927e3adcf8fSFrançois Tigeot if (depth < 0) 928e3adcf8fSFrançois Tigeot return depth; 929e3adcf8fSFrançois Tigeot 930e3adcf8fSFrançois Tigeot /* ignore UV planes */ 931e3adcf8fSFrançois Tigeot rec->stride_UV = 0; 932e3adcf8fSFrançois Tigeot rec->offset_U = 0; 933e3adcf8fSFrançois Tigeot rec->offset_V = 0; 934e3adcf8fSFrançois Tigeot /* check pixel alignment */ 935e3adcf8fSFrançois Tigeot if (rec->offset_Y % depth) 936e3adcf8fSFrançois Tigeot return -EINVAL; 937e3adcf8fSFrançois Tigeot break; 938e3adcf8fSFrançois Tigeot 939e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PLANAR: 940e3adcf8fSFrançois Tigeot if (uv_vscale < 0 || uv_hscale < 0) 941e3adcf8fSFrançois Tigeot return -EINVAL; 942e3adcf8fSFrançois Tigeot /* no offset restrictions for planar formats */ 943e3adcf8fSFrançois Tigeot break; 944e3adcf8fSFrançois Tigeot 945e3adcf8fSFrançois Tigeot default: 946e3adcf8fSFrançois Tigeot return -EINVAL; 947e3adcf8fSFrançois Tigeot } 948e3adcf8fSFrançois Tigeot 949e3adcf8fSFrançois Tigeot if (rec->src_width % uv_hscale) 950e3adcf8fSFrançois Tigeot return -EINVAL; 951e3adcf8fSFrançois Tigeot 952e3adcf8fSFrançois Tigeot /* stride checking */ 953e3adcf8fSFrançois Tigeot if (IS_I830(dev) || IS_845G(dev)) 954e3adcf8fSFrançois Tigeot stride_mask = 255; 955e3adcf8fSFrançois Tigeot else 956e3adcf8fSFrançois Tigeot stride_mask = 63; 957e3adcf8fSFrançois Tigeot 958e3adcf8fSFrançois Tigeot if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) 959e3adcf8fSFrançois Tigeot return -EINVAL; 960e3adcf8fSFrançois Tigeot if (IS_GEN4(dev) && rec->stride_Y < 512) 961e3adcf8fSFrançois Tigeot return -EINVAL; 962e3adcf8fSFrançois Tigeot 963e3adcf8fSFrançois Tigeot tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? 964e3adcf8fSFrançois Tigeot 4096 : 8192; 965e3adcf8fSFrançois Tigeot if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) 966e3adcf8fSFrançois Tigeot return -EINVAL; 967e3adcf8fSFrançois Tigeot 968e3adcf8fSFrançois Tigeot /* check buffer dimensions */ 969e3adcf8fSFrançois Tigeot switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 970e3adcf8fSFrançois Tigeot case I915_OVERLAY_RGB: 971e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PACKED: 972e3adcf8fSFrançois Tigeot /* always 4 Y values per depth pixels */ 973e3adcf8fSFrançois Tigeot if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) 974e3adcf8fSFrançois Tigeot return -EINVAL; 975e3adcf8fSFrançois Tigeot 976e3adcf8fSFrançois Tigeot tmp = rec->stride_Y*rec->src_height; 977e3adcf8fSFrançois Tigeot if (rec->offset_Y + tmp > new_bo->base.size) 978e3adcf8fSFrançois Tigeot return -EINVAL; 979e3adcf8fSFrançois Tigeot break; 980e3adcf8fSFrançois Tigeot 981e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PLANAR: 982e3adcf8fSFrançois Tigeot if (rec->src_width > rec->stride_Y) 983e3adcf8fSFrançois Tigeot return -EINVAL; 984e3adcf8fSFrançois Tigeot if (rec->src_width/uv_hscale > rec->stride_UV) 985e3adcf8fSFrançois Tigeot return -EINVAL; 986e3adcf8fSFrançois Tigeot 987e3adcf8fSFrançois Tigeot tmp = rec->stride_Y * rec->src_height; 988e3adcf8fSFrançois Tigeot if (rec->offset_Y + tmp > new_bo->base.size) 989e3adcf8fSFrançois Tigeot return -EINVAL; 990e3adcf8fSFrançois Tigeot 991e3adcf8fSFrançois Tigeot tmp = rec->stride_UV * (rec->src_height / uv_vscale); 992e3adcf8fSFrançois Tigeot if (rec->offset_U + tmp > new_bo->base.size || 993e3adcf8fSFrançois Tigeot rec->offset_V + tmp > new_bo->base.size) 994e3adcf8fSFrançois Tigeot return -EINVAL; 995e3adcf8fSFrançois Tigeot break; 996e3adcf8fSFrançois Tigeot } 997e3adcf8fSFrançois Tigeot 998e3adcf8fSFrançois Tigeot return 0; 999e3adcf8fSFrançois Tigeot } 1000e3adcf8fSFrançois Tigeot 1001e3adcf8fSFrançois Tigeot /** 1002e3adcf8fSFrançois Tigeot * Return the pipe currently connected to the panel fitter, 1003e3adcf8fSFrançois Tigeot * or -1 if the panel fitter is not present or not in use 1004e3adcf8fSFrançois Tigeot */ 1005e3adcf8fSFrançois Tigeot static int intel_panel_fitter_pipe(struct drm_device *dev) 1006e3adcf8fSFrançois Tigeot { 1007e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1008e3adcf8fSFrançois Tigeot u32 pfit_control; 1009e3adcf8fSFrançois Tigeot 1010e3adcf8fSFrançois Tigeot /* i830 doesn't have a panel fitter */ 1011e3adcf8fSFrançois Tigeot if (IS_I830(dev)) 1012e3adcf8fSFrançois Tigeot return -1; 1013e3adcf8fSFrançois Tigeot 1014e3adcf8fSFrançois Tigeot pfit_control = I915_READ(PFIT_CONTROL); 1015e3adcf8fSFrançois Tigeot 1016e3adcf8fSFrançois Tigeot /* See if the panel fitter is in use */ 1017e3adcf8fSFrançois Tigeot if ((pfit_control & PFIT_ENABLE) == 0) 1018e3adcf8fSFrançois Tigeot return -1; 1019e3adcf8fSFrançois Tigeot 1020e3adcf8fSFrançois Tigeot /* 965 can place panel fitter on either pipe */ 1021e3adcf8fSFrançois Tigeot if (IS_GEN4(dev)) 1022e3adcf8fSFrançois Tigeot return (pfit_control >> 29) & 0x3; 1023e3adcf8fSFrançois Tigeot 1024e3adcf8fSFrançois Tigeot /* older chips can only use pipe 1 */ 1025e3adcf8fSFrançois Tigeot return 1; 1026e3adcf8fSFrançois Tigeot } 1027e3adcf8fSFrançois Tigeot 1028e3adcf8fSFrançois Tigeot int intel_overlay_put_image(struct drm_device *dev, void *data, 1029e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1030e3adcf8fSFrançois Tigeot { 1031e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *put_image_rec = data; 1032e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 1033e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1034e3adcf8fSFrançois Tigeot struct drm_mode_object *drmmode_obj; 1035e3adcf8fSFrançois Tigeot struct intel_crtc *crtc; 1036e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo; 1037e3adcf8fSFrançois Tigeot struct put_image_params *params; 1038e3adcf8fSFrançois Tigeot int ret; 1039e3adcf8fSFrançois Tigeot 1040*e3440f96SFrançois Tigeot /* No need to check for DRIVER_MODESET - we don't set it up then. */ 1041e3adcf8fSFrançois Tigeot overlay = dev_priv->overlay; 1042e3adcf8fSFrançois Tigeot if (!overlay) { 1043e3adcf8fSFrançois Tigeot DRM_DEBUG("userspace bug: no overlay\n"); 1044e3adcf8fSFrançois Tigeot return -ENODEV; 1045e3adcf8fSFrançois Tigeot } 1046e3adcf8fSFrançois Tigeot 1047e3adcf8fSFrançois Tigeot if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { 1048af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); 1049e3adcf8fSFrançois Tigeot DRM_LOCK(dev); 1050e3adcf8fSFrançois Tigeot 1051e3adcf8fSFrançois Tigeot ret = intel_overlay_switch_off(overlay); 1052e3adcf8fSFrançois Tigeot 1053e3adcf8fSFrançois Tigeot DRM_UNLOCK(dev); 1054af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_RELEASE); 1055e3adcf8fSFrançois Tigeot 1056e3adcf8fSFrançois Tigeot return ret; 1057e3adcf8fSFrançois Tigeot } 1058e3adcf8fSFrançois Tigeot 10595a3b77d5SFrançois Tigeot params = kmalloc(sizeof(struct put_image_params), M_DRM, 1060e3adcf8fSFrançois Tigeot M_WAITOK | M_ZERO); 1061*e3440f96SFrançois Tigeot if (!params) 1062*e3440f96SFrançois Tigeot return -ENOMEM; 1063e3adcf8fSFrançois Tigeot 1064e3adcf8fSFrançois Tigeot drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, 1065e3adcf8fSFrançois Tigeot DRM_MODE_OBJECT_CRTC); 1066e3adcf8fSFrançois Tigeot if (!drmmode_obj) { 1067e3adcf8fSFrançois Tigeot ret = -ENOENT; 1068e3adcf8fSFrançois Tigeot goto out_free; 1069e3adcf8fSFrançois Tigeot } 1070e3adcf8fSFrançois Tigeot crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); 1071e3adcf8fSFrançois Tigeot 1072e3adcf8fSFrançois Tigeot new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv, 1073e3adcf8fSFrançois Tigeot put_image_rec->bo_handle)); 1074e3adcf8fSFrançois Tigeot if (&new_bo->base == NULL) { 1075e3adcf8fSFrançois Tigeot ret = -ENOENT; 1076e3adcf8fSFrançois Tigeot goto out_free; 1077e3adcf8fSFrançois Tigeot } 1078e3adcf8fSFrançois Tigeot 1079af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); 1080e3adcf8fSFrançois Tigeot DRM_LOCK(dev); 1081e3adcf8fSFrançois Tigeot 1082e3adcf8fSFrançois Tigeot if (new_bo->tiling_mode) { 1083e3adcf8fSFrançois Tigeot DRM_ERROR("buffer used for overlay image can not be tiled\n"); 1084e3adcf8fSFrançois Tigeot ret = -EINVAL; 1085e3adcf8fSFrançois Tigeot goto out_unlock; 1086e3adcf8fSFrançois Tigeot } 1087e3adcf8fSFrançois Tigeot 1088e3adcf8fSFrançois Tigeot ret = intel_overlay_recover_from_interrupt(overlay); 1089e3adcf8fSFrançois Tigeot if (ret != 0) 1090e3adcf8fSFrançois Tigeot goto out_unlock; 1091e3adcf8fSFrançois Tigeot 1092e3adcf8fSFrançois Tigeot if (overlay->crtc != crtc) { 1093e3adcf8fSFrançois Tigeot struct drm_display_mode *mode = &crtc->base.mode; 1094e3adcf8fSFrançois Tigeot ret = intel_overlay_switch_off(overlay); 1095e3adcf8fSFrançois Tigeot if (ret != 0) 1096e3adcf8fSFrançois Tigeot goto out_unlock; 1097e3adcf8fSFrançois Tigeot 1098e3adcf8fSFrançois Tigeot ret = check_overlay_possible_on_crtc(overlay, crtc); 1099e3adcf8fSFrançois Tigeot if (ret != 0) 1100e3adcf8fSFrançois Tigeot goto out_unlock; 1101e3adcf8fSFrançois Tigeot 1102e3adcf8fSFrançois Tigeot overlay->crtc = crtc; 1103e3adcf8fSFrançois Tigeot crtc->overlay = overlay; 1104e3adcf8fSFrançois Tigeot 1105e3adcf8fSFrançois Tigeot /* line too wide, i.e. one-line-mode */ 1106e3adcf8fSFrançois Tigeot if (mode->hdisplay > 1024 && 1107e3adcf8fSFrançois Tigeot intel_panel_fitter_pipe(dev) == crtc->pipe) { 1108e3adcf8fSFrançois Tigeot overlay->pfit_active = 1; 1109e3adcf8fSFrançois Tigeot update_pfit_vscale_ratio(overlay); 1110e3adcf8fSFrançois Tigeot } else 1111e3adcf8fSFrançois Tigeot overlay->pfit_active = 0; 1112e3adcf8fSFrançois Tigeot } 1113e3adcf8fSFrançois Tigeot 1114e3adcf8fSFrançois Tigeot ret = check_overlay_dst(overlay, put_image_rec); 1115e3adcf8fSFrançois Tigeot if (ret != 0) 1116e3adcf8fSFrançois Tigeot goto out_unlock; 1117e3adcf8fSFrançois Tigeot 1118e3adcf8fSFrançois Tigeot if (overlay->pfit_active) { 1119e3adcf8fSFrançois Tigeot params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / 1120e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio); 1121e3adcf8fSFrançois Tigeot /* shifting right rounds downwards, so add 1 */ 1122e3adcf8fSFrançois Tigeot params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / 1123e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio) + 1; 1124e3adcf8fSFrançois Tigeot } else { 1125e3adcf8fSFrançois Tigeot params->dst_y = put_image_rec->dst_y; 1126e3adcf8fSFrançois Tigeot params->dst_h = put_image_rec->dst_height; 1127e3adcf8fSFrançois Tigeot } 1128e3adcf8fSFrançois Tigeot params->dst_x = put_image_rec->dst_x; 1129e3adcf8fSFrançois Tigeot params->dst_w = put_image_rec->dst_width; 1130e3adcf8fSFrançois Tigeot 1131e3adcf8fSFrançois Tigeot params->src_w = put_image_rec->src_width; 1132e3adcf8fSFrançois Tigeot params->src_h = put_image_rec->src_height; 1133e3adcf8fSFrançois Tigeot params->src_scan_w = put_image_rec->src_scan_width; 1134e3adcf8fSFrançois Tigeot params->src_scan_h = put_image_rec->src_scan_height; 1135e3adcf8fSFrançois Tigeot if (params->src_scan_h > params->src_h || 1136e3adcf8fSFrançois Tigeot params->src_scan_w > params->src_w) { 1137e3adcf8fSFrançois Tigeot ret = -EINVAL; 1138e3adcf8fSFrançois Tigeot goto out_unlock; 1139e3adcf8fSFrançois Tigeot } 1140e3adcf8fSFrançois Tigeot 1141e3adcf8fSFrançois Tigeot ret = check_overlay_src(dev, put_image_rec, new_bo); 1142e3adcf8fSFrançois Tigeot if (ret != 0) 1143e3adcf8fSFrançois Tigeot goto out_unlock; 1144e3adcf8fSFrançois Tigeot params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK; 1145e3adcf8fSFrançois Tigeot params->stride_Y = put_image_rec->stride_Y; 1146e3adcf8fSFrançois Tigeot params->stride_UV = put_image_rec->stride_UV; 1147e3adcf8fSFrançois Tigeot params->offset_Y = put_image_rec->offset_Y; 1148e3adcf8fSFrançois Tigeot params->offset_U = put_image_rec->offset_U; 1149e3adcf8fSFrançois Tigeot params->offset_V = put_image_rec->offset_V; 1150e3adcf8fSFrançois Tigeot 1151e3adcf8fSFrançois Tigeot /* Check scaling after src size to prevent a divide-by-zero. */ 1152e3adcf8fSFrançois Tigeot ret = check_overlay_scaling(params); 1153e3adcf8fSFrançois Tigeot if (ret != 0) 1154e3adcf8fSFrançois Tigeot goto out_unlock; 1155e3adcf8fSFrançois Tigeot 1156e3adcf8fSFrançois Tigeot ret = intel_overlay_do_put_image(overlay, new_bo, params); 1157e3adcf8fSFrançois Tigeot if (ret != 0) 1158e3adcf8fSFrançois Tigeot goto out_unlock; 1159e3adcf8fSFrançois Tigeot 1160e3adcf8fSFrançois Tigeot DRM_UNLOCK(dev); 1161af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_RELEASE); 1162e3adcf8fSFrançois Tigeot 1163*e3440f96SFrançois Tigeot kfree(params, M_DRM); 1164e3adcf8fSFrançois Tigeot 1165e3adcf8fSFrançois Tigeot return 0; 1166e3adcf8fSFrançois Tigeot 1167e3adcf8fSFrançois Tigeot out_unlock: 1168e3adcf8fSFrançois Tigeot DRM_UNLOCK(dev); 1169af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_RELEASE); 1170e3adcf8fSFrançois Tigeot drm_gem_object_unreference_unlocked(&new_bo->base); 1171e3adcf8fSFrançois Tigeot out_free: 1172*e3440f96SFrançois Tigeot kfree(params, M_DRM); 1173e3adcf8fSFrançois Tigeot 1174e3adcf8fSFrançois Tigeot return ret; 1175e3adcf8fSFrançois Tigeot } 1176e3adcf8fSFrançois Tigeot 1177e3adcf8fSFrançois Tigeot static void update_reg_attrs(struct intel_overlay *overlay, 1178*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 1179e3adcf8fSFrançois Tigeot { 1180*e3440f96SFrançois Tigeot iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff), 1181*e3440f96SFrançois Tigeot ®s->OCLRC0); 1182*e3440f96SFrançois Tigeot iowrite32(overlay->saturation, ®s->OCLRC1); 1183e3adcf8fSFrançois Tigeot } 1184e3adcf8fSFrançois Tigeot 1185e3adcf8fSFrançois Tigeot static bool check_gamma_bounds(u32 gamma1, u32 gamma2) 1186e3adcf8fSFrançois Tigeot { 1187e3adcf8fSFrançois Tigeot int i; 1188e3adcf8fSFrançois Tigeot 1189e3adcf8fSFrançois Tigeot if (gamma1 & 0xff000000 || gamma2 & 0xff000000) 1190e3adcf8fSFrançois Tigeot return false; 1191e3adcf8fSFrançois Tigeot 1192e3adcf8fSFrançois Tigeot for (i = 0; i < 3; i++) { 1193e3adcf8fSFrançois Tigeot if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) 1194e3adcf8fSFrançois Tigeot return false; 1195e3adcf8fSFrançois Tigeot } 1196e3adcf8fSFrançois Tigeot 1197e3adcf8fSFrançois Tigeot return true; 1198e3adcf8fSFrançois Tigeot } 1199e3adcf8fSFrançois Tigeot 1200e3adcf8fSFrançois Tigeot static bool check_gamma5_errata(u32 gamma5) 1201e3adcf8fSFrançois Tigeot { 1202e3adcf8fSFrançois Tigeot int i; 1203e3adcf8fSFrançois Tigeot 1204e3adcf8fSFrançois Tigeot for (i = 0; i < 3; i++) { 1205e3adcf8fSFrançois Tigeot if (((gamma5 >> i*8) & 0xff) == 0x80) 1206e3adcf8fSFrançois Tigeot return false; 1207e3adcf8fSFrançois Tigeot } 1208e3adcf8fSFrançois Tigeot 1209e3adcf8fSFrançois Tigeot return true; 1210e3adcf8fSFrançois Tigeot } 1211e3adcf8fSFrançois Tigeot 1212e3adcf8fSFrançois Tigeot static int check_gamma(struct drm_intel_overlay_attrs *attrs) 1213e3adcf8fSFrançois Tigeot { 1214e3adcf8fSFrançois Tigeot if (!check_gamma_bounds(0, attrs->gamma0) || 1215e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || 1216e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || 1217e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || 1218e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || 1219e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || 1220e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) 1221e3adcf8fSFrançois Tigeot return -EINVAL; 1222e3adcf8fSFrançois Tigeot 1223e3adcf8fSFrançois Tigeot if (!check_gamma5_errata(attrs->gamma5)) 1224e3adcf8fSFrançois Tigeot return -EINVAL; 1225e3adcf8fSFrançois Tigeot 1226e3adcf8fSFrançois Tigeot return 0; 1227e3adcf8fSFrançois Tigeot } 1228e3adcf8fSFrançois Tigeot 1229e3adcf8fSFrançois Tigeot int intel_overlay_attrs(struct drm_device *dev, void *data, 1230e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1231e3adcf8fSFrançois Tigeot { 1232e3adcf8fSFrançois Tigeot struct drm_intel_overlay_attrs *attrs = data; 1233e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 1234e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1235*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1236e3adcf8fSFrançois Tigeot int ret; 1237e3adcf8fSFrançois Tigeot 1238*e3440f96SFrançois Tigeot /* No need to check for DRIVER_MODESET - we don't set it up then. */ 1239e3adcf8fSFrançois Tigeot overlay = dev_priv->overlay; 1240e3adcf8fSFrançois Tigeot if (!overlay) { 1241e3adcf8fSFrançois Tigeot DRM_DEBUG("userspace bug: no overlay\n"); 1242e3adcf8fSFrançois Tigeot return -ENODEV; 1243e3adcf8fSFrançois Tigeot } 1244e3adcf8fSFrançois Tigeot 1245af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); 1246e3adcf8fSFrançois Tigeot DRM_LOCK(dev); 1247e3adcf8fSFrançois Tigeot 1248e3adcf8fSFrançois Tigeot ret = -EINVAL; 1249e3adcf8fSFrançois Tigeot if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { 1250e3adcf8fSFrançois Tigeot attrs->color_key = overlay->color_key; 1251e3adcf8fSFrançois Tigeot attrs->brightness = overlay->brightness; 1252e3adcf8fSFrançois Tigeot attrs->contrast = overlay->contrast; 1253e3adcf8fSFrançois Tigeot attrs->saturation = overlay->saturation; 1254e3adcf8fSFrançois Tigeot 1255e3adcf8fSFrançois Tigeot if (!IS_GEN2(dev)) { 1256e3adcf8fSFrançois Tigeot attrs->gamma0 = I915_READ(OGAMC0); 1257e3adcf8fSFrançois Tigeot attrs->gamma1 = I915_READ(OGAMC1); 1258e3adcf8fSFrançois Tigeot attrs->gamma2 = I915_READ(OGAMC2); 1259e3adcf8fSFrançois Tigeot attrs->gamma3 = I915_READ(OGAMC3); 1260e3adcf8fSFrançois Tigeot attrs->gamma4 = I915_READ(OGAMC4); 1261e3adcf8fSFrançois Tigeot attrs->gamma5 = I915_READ(OGAMC5); 1262e3adcf8fSFrançois Tigeot } 1263e3adcf8fSFrançois Tigeot } else { 1264e3adcf8fSFrançois Tigeot if (attrs->brightness < -128 || attrs->brightness > 127) 1265e3adcf8fSFrançois Tigeot goto out_unlock; 1266e3adcf8fSFrançois Tigeot if (attrs->contrast > 255) 1267e3adcf8fSFrançois Tigeot goto out_unlock; 1268e3adcf8fSFrançois Tigeot if (attrs->saturation > 1023) 1269e3adcf8fSFrançois Tigeot goto out_unlock; 1270e3adcf8fSFrançois Tigeot 1271e3adcf8fSFrançois Tigeot overlay->color_key = attrs->color_key; 1272e3adcf8fSFrançois Tigeot overlay->brightness = attrs->brightness; 1273e3adcf8fSFrançois Tigeot overlay->contrast = attrs->contrast; 1274e3adcf8fSFrançois Tigeot overlay->saturation = attrs->saturation; 1275e3adcf8fSFrançois Tigeot 1276e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 1277e3adcf8fSFrançois Tigeot if (!regs) { 1278e3adcf8fSFrançois Tigeot ret = -ENOMEM; 1279e3adcf8fSFrançois Tigeot goto out_unlock; 1280e3adcf8fSFrançois Tigeot } 1281e3adcf8fSFrançois Tigeot 1282e3adcf8fSFrançois Tigeot update_reg_attrs(overlay, regs); 1283e3adcf8fSFrançois Tigeot 1284e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 1285e3adcf8fSFrançois Tigeot 1286e3adcf8fSFrançois Tigeot if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { 1287e3adcf8fSFrançois Tigeot if (IS_GEN2(dev)) 1288e3adcf8fSFrançois Tigeot goto out_unlock; 1289e3adcf8fSFrançois Tigeot 1290e3adcf8fSFrançois Tigeot if (overlay->active) { 1291e3adcf8fSFrançois Tigeot ret = -EBUSY; 1292e3adcf8fSFrançois Tigeot goto out_unlock; 1293e3adcf8fSFrançois Tigeot } 1294e3adcf8fSFrançois Tigeot 1295e3adcf8fSFrançois Tigeot ret = check_gamma(attrs); 1296e3adcf8fSFrançois Tigeot if (ret) 1297e3adcf8fSFrançois Tigeot goto out_unlock; 1298e3adcf8fSFrançois Tigeot 1299e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC0, attrs->gamma0); 1300e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC1, attrs->gamma1); 1301e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC2, attrs->gamma2); 1302e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC3, attrs->gamma3); 1303e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC4, attrs->gamma4); 1304e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC5, attrs->gamma5); 1305e3adcf8fSFrançois Tigeot } 1306e3adcf8fSFrançois Tigeot } 1307e3adcf8fSFrançois Tigeot 1308e3adcf8fSFrançois Tigeot ret = 0; 1309e3adcf8fSFrançois Tigeot out_unlock: 1310e3adcf8fSFrançois Tigeot DRM_UNLOCK(dev); 1311af4b81b9SFrançois Tigeot lockmgr(&dev->mode_config.mutex, LK_RELEASE); 1312e3adcf8fSFrançois Tigeot 1313e3adcf8fSFrançois Tigeot return ret; 1314e3adcf8fSFrançois Tigeot } 1315e3adcf8fSFrançois Tigeot 1316e3adcf8fSFrançois Tigeot void intel_setup_overlay(struct drm_device *dev) 1317e3adcf8fSFrançois Tigeot { 1318e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 1319e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1320e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *reg_bo; 1321*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1322e3adcf8fSFrançois Tigeot int ret; 1323e3adcf8fSFrançois Tigeot 1324e3adcf8fSFrançois Tigeot if (!HAS_OVERLAY(dev)) 1325e3adcf8fSFrançois Tigeot return; 1326e3adcf8fSFrançois Tigeot 13275a3b77d5SFrançois Tigeot overlay = kmalloc(sizeof(struct intel_overlay), M_DRM, 1328e3adcf8fSFrançois Tigeot M_WAITOK | M_ZERO); 1329*e3440f96SFrançois Tigeot if (!overlay) 1330*e3440f96SFrançois Tigeot return; 1331*e3440f96SFrançois Tigeot 1332e3adcf8fSFrançois Tigeot DRM_LOCK(dev); 1333*e3440f96SFrançois Tigeot if (WARN_ON(dev_priv->overlay)) 1334e3adcf8fSFrançois Tigeot goto out_free; 1335*e3440f96SFrançois Tigeot 1336e3adcf8fSFrançois Tigeot overlay->dev = dev; 1337e3adcf8fSFrançois Tigeot 1338e3adcf8fSFrançois Tigeot reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE); 1339e3adcf8fSFrançois Tigeot if (!reg_bo) 1340e3adcf8fSFrançois Tigeot goto out_free; 1341e3adcf8fSFrançois Tigeot overlay->reg_bo = reg_bo; 1342e3adcf8fSFrançois Tigeot 1343e3adcf8fSFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(dev)) { 1344e3adcf8fSFrançois Tigeot ret = i915_gem_attach_phys_object(dev, reg_bo, 1345e3adcf8fSFrançois Tigeot I915_GEM_PHYS_OVERLAY_REGS, 1346e3adcf8fSFrançois Tigeot PAGE_SIZE); 1347e3adcf8fSFrançois Tigeot if (ret) { 1348e3adcf8fSFrançois Tigeot DRM_ERROR("failed to attach phys overlay regs\n"); 1349e3adcf8fSFrançois Tigeot goto out_free_bo; 1350e3adcf8fSFrançois Tigeot } 1351e3adcf8fSFrançois Tigeot overlay->flip_addr = reg_bo->phys_obj->handle->busaddr; 1352e3adcf8fSFrançois Tigeot } else { 1353b00bc81cSFrançois Tigeot ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false); 1354e3adcf8fSFrançois Tigeot if (ret) { 1355e3adcf8fSFrançois Tigeot DRM_ERROR("failed to pin overlay register bo\n"); 1356e3adcf8fSFrançois Tigeot goto out_free_bo; 1357e3adcf8fSFrançois Tigeot } 1358e3adcf8fSFrançois Tigeot overlay->flip_addr = reg_bo->gtt_offset; 1359e3adcf8fSFrançois Tigeot 1360e3adcf8fSFrançois Tigeot ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); 1361e3adcf8fSFrançois Tigeot if (ret) { 1362e3adcf8fSFrançois Tigeot DRM_ERROR("failed to move overlay register bo into the GTT\n"); 1363e3adcf8fSFrançois Tigeot goto out_unpin_bo; 1364e3adcf8fSFrançois Tigeot } 1365e3adcf8fSFrançois Tigeot } 1366e3adcf8fSFrançois Tigeot 1367e3adcf8fSFrançois Tigeot /* init all values */ 1368e3adcf8fSFrançois Tigeot overlay->color_key = 0x0101fe; 1369e3adcf8fSFrançois Tigeot overlay->brightness = -19; 1370e3adcf8fSFrançois Tigeot overlay->contrast = 75; 1371e3adcf8fSFrançois Tigeot overlay->saturation = 146; 1372e3adcf8fSFrançois Tigeot 1373e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 1374e3adcf8fSFrançois Tigeot if (!regs) 1375e3adcf8fSFrançois Tigeot goto out_unpin_bo; 1376e3adcf8fSFrançois Tigeot 1377*e3440f96SFrançois Tigeot memset_io(regs, 0, sizeof(struct overlay_registers)); 1378e3adcf8fSFrançois Tigeot update_polyphase_filter(regs); 1379e3adcf8fSFrançois Tigeot update_reg_attrs(overlay, regs); 1380e3adcf8fSFrançois Tigeot 1381e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 1382e3adcf8fSFrançois Tigeot 1383e3adcf8fSFrançois Tigeot dev_priv->overlay = overlay; 1384e3adcf8fSFrançois Tigeot DRM_UNLOCK(dev); 1385*e3440f96SFrançois Tigeot DRM_INFO("initialized overlay support\n"); 1386e3adcf8fSFrançois Tigeot return; 1387e3adcf8fSFrançois Tigeot 1388e3adcf8fSFrançois Tigeot out_unpin_bo: 1389e3adcf8fSFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(dev)) 1390e3adcf8fSFrançois Tigeot i915_gem_object_unpin(reg_bo); 1391e3adcf8fSFrançois Tigeot out_free_bo: 1392e3adcf8fSFrançois Tigeot drm_gem_object_unreference(®_bo->base); 1393e3adcf8fSFrançois Tigeot out_free: 1394e3adcf8fSFrançois Tigeot DRM_UNLOCK(dev); 1395*e3440f96SFrançois Tigeot kfree(overlay, M_DRM); 1396e3adcf8fSFrançois Tigeot return; 1397e3adcf8fSFrançois Tigeot } 1398e3adcf8fSFrançois Tigeot 1399e3adcf8fSFrançois Tigeot void intel_cleanup_overlay(struct drm_device *dev) 1400e3adcf8fSFrançois Tigeot { 1401e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 1402e3adcf8fSFrançois Tigeot 1403e3adcf8fSFrançois Tigeot if (!dev_priv->overlay) 1404e3adcf8fSFrançois Tigeot return; 1405e3adcf8fSFrançois Tigeot 1406e3adcf8fSFrançois Tigeot /* The bo's should be free'd by the generic code already. 1407e3adcf8fSFrançois Tigeot * Furthermore modesetting teardown happens beforehand so the 1408e3adcf8fSFrançois Tigeot * hardware should be off already */ 1409*e3440f96SFrançois Tigeot BUG_ON(dev_priv->overlay->active); 1410e3adcf8fSFrançois Tigeot 1411e3adcf8fSFrançois Tigeot drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base); 1412*e3440f96SFrançois Tigeot kfree(dev_priv->overlay, M_DRM); 1413e3adcf8fSFrançois Tigeot } 1414e3adcf8fSFrançois Tigeot 14153f2f609dSFrançois Tigeot #ifdef CONFIG_DEBUG_FS 14163f2f609dSFrançois Tigeot #include <linux/seq_file.h> 14173f2f609dSFrançois Tigeot 1418e3adcf8fSFrançois Tigeot struct intel_overlay_error_state { 1419e3adcf8fSFrançois Tigeot struct overlay_registers regs; 1420e3adcf8fSFrançois Tigeot unsigned long base; 1421e3adcf8fSFrançois Tigeot u32 dovsta; 1422e3adcf8fSFrançois Tigeot u32 isr; 1423e3adcf8fSFrançois Tigeot }; 1424e3adcf8fSFrançois Tigeot 1425*e3440f96SFrançois Tigeot static struct overlay_registers __iomem * 1426*e3440f96SFrançois Tigeot intel_overlay_map_regs_atomic(struct intel_overlay *overlay) 1427*e3440f96SFrançois Tigeot { 1428*e3440f96SFrançois Tigeot drm_i915_private_t *dev_priv = overlay->dev->dev_private; 1429*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1430*e3440f96SFrançois Tigeot 1431*e3440f96SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 1432*e3440f96SFrançois Tigeot /* Cast to make sparse happy, but it's wc memory anyway, so 1433*e3440f96SFrançois Tigeot * equivalent to the wc io mapping on X86. */ 1434*e3440f96SFrançois Tigeot regs = (struct overlay_registers __iomem *) 1435*e3440f96SFrançois Tigeot overlay->reg_bo->phys_obj->handle->vaddr; 1436*e3440f96SFrançois Tigeot else 1437*e3440f96SFrançois Tigeot regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, 1438*e3440f96SFrançois Tigeot overlay->reg_bo->gtt_offset); 1439*e3440f96SFrançois Tigeot 1440*e3440f96SFrançois Tigeot return regs; 1441*e3440f96SFrançois Tigeot } 1442*e3440f96SFrançois Tigeot 1443*e3440f96SFrançois Tigeot static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, 1444*e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 1445*e3440f96SFrançois Tigeot { 1446*e3440f96SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 1447*e3440f96SFrançois Tigeot io_mapping_unmap_atomic(regs); 1448*e3440f96SFrançois Tigeot } 1449*e3440f96SFrançois Tigeot 1450*e3440f96SFrançois Tigeot 1451e3adcf8fSFrançois Tigeot struct intel_overlay_error_state * 1452e3adcf8fSFrançois Tigeot intel_overlay_capture_error_state(struct drm_device *dev) 1453e3adcf8fSFrançois Tigeot { 1454e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 1455e3adcf8fSFrançois Tigeot struct intel_overlay *overlay = dev_priv->overlay; 1456e3adcf8fSFrançois Tigeot struct intel_overlay_error_state *error; 1457e3adcf8fSFrançois Tigeot struct overlay_registers __iomem *regs; 1458e3adcf8fSFrançois Tigeot 1459e3adcf8fSFrançois Tigeot if (!overlay || !overlay->active) 1460e3adcf8fSFrançois Tigeot return NULL; 1461e3adcf8fSFrançois Tigeot 14625a3b77d5SFrançois Tigeot error = kmalloc(sizeof(*error), M_DRM, M_NOWAIT); 1463e3adcf8fSFrançois Tigeot if (error == NULL) 1464e3adcf8fSFrançois Tigeot return NULL; 1465e3adcf8fSFrançois Tigeot 1466e3adcf8fSFrançois Tigeot error->dovsta = I915_READ(DOVSTA); 1467e3adcf8fSFrançois Tigeot error->isr = I915_READ(ISR); 1468e3adcf8fSFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 1469*e3440f96SFrançois Tigeot error->base = (__force long)overlay->reg_bo->phys_obj->handle->vaddr; 1470e3adcf8fSFrançois Tigeot else 1471*e3440f96SFrançois Tigeot error->base = overlay->reg_bo->gtt_offset; 1472e3adcf8fSFrançois Tigeot 1473*e3440f96SFrançois Tigeot regs = intel_overlay_map_regs_atomic(overlay); 1474e3adcf8fSFrançois Tigeot if (!regs) 1475e3adcf8fSFrançois Tigeot goto err; 1476e3adcf8fSFrançois Tigeot 1477*e3440f96SFrançois Tigeot memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); 1478*e3440f96SFrançois Tigeot intel_overlay_unmap_regs_atomic(overlay, regs); 1479e3adcf8fSFrançois Tigeot 1480*e3440f96SFrançois Tigeot return error; 1481e3adcf8fSFrançois Tigeot 1482e3adcf8fSFrançois Tigeot err: 1483*e3440f96SFrançois Tigeot kfree(error, M_DRM); 1484*e3440f96SFrançois Tigeot return NULL; 1485e3adcf8fSFrançois Tigeot } 1486e3adcf8fSFrançois Tigeot 1487e3adcf8fSFrançois Tigeot void 1488*e3440f96SFrançois Tigeot intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error) 1489e3adcf8fSFrançois Tigeot { 1490*e3440f96SFrançois Tigeot seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", 1491e3adcf8fSFrançois Tigeot error->dovsta, error->isr); 1492*e3440f96SFrançois Tigeot seq_printf(m, " Register file at 0x%08lx:\n", 1493e3adcf8fSFrançois Tigeot error->base); 1494e3adcf8fSFrançois Tigeot 1495*e3440f96SFrançois Tigeot #define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x) 1496e3adcf8fSFrançois Tigeot P(OBUF_0Y); 1497e3adcf8fSFrançois Tigeot P(OBUF_1Y); 1498e3adcf8fSFrançois Tigeot P(OBUF_0U); 1499e3adcf8fSFrançois Tigeot P(OBUF_0V); 1500e3adcf8fSFrançois Tigeot P(OBUF_1U); 1501e3adcf8fSFrançois Tigeot P(OBUF_1V); 1502e3adcf8fSFrançois Tigeot P(OSTRIDE); 1503e3adcf8fSFrançois Tigeot P(YRGB_VPH); 1504e3adcf8fSFrançois Tigeot P(UV_VPH); 1505e3adcf8fSFrançois Tigeot P(HORZ_PH); 1506e3adcf8fSFrançois Tigeot P(INIT_PHS); 1507e3adcf8fSFrançois Tigeot P(DWINPOS); 1508e3adcf8fSFrançois Tigeot P(DWINSZ); 1509e3adcf8fSFrançois Tigeot P(SWIDTH); 1510e3adcf8fSFrançois Tigeot P(SWIDTHSW); 1511e3adcf8fSFrançois Tigeot P(SHEIGHT); 1512e3adcf8fSFrançois Tigeot P(YRGBSCALE); 1513e3adcf8fSFrançois Tigeot P(UVSCALE); 1514e3adcf8fSFrançois Tigeot P(OCLRC0); 1515e3adcf8fSFrançois Tigeot P(OCLRC1); 1516e3adcf8fSFrançois Tigeot P(DCLRKV); 1517e3adcf8fSFrançois Tigeot P(DCLRKM); 1518e3adcf8fSFrançois Tigeot P(SCLRKVH); 1519e3adcf8fSFrançois Tigeot P(SCLRKVL); 1520e3adcf8fSFrançois Tigeot P(SCLRKEN); 1521e3adcf8fSFrançois Tigeot P(OCONFIG); 1522e3adcf8fSFrançois Tigeot P(OCMD); 1523e3adcf8fSFrançois Tigeot P(OSTART_0Y); 1524e3adcf8fSFrançois Tigeot P(OSTART_1Y); 1525e3adcf8fSFrançois Tigeot P(OSTART_0U); 1526e3adcf8fSFrançois Tigeot P(OSTART_0V); 1527e3adcf8fSFrançois Tigeot P(OSTART_1U); 1528e3adcf8fSFrançois Tigeot P(OSTART_1V); 1529e3adcf8fSFrançois Tigeot P(OTILEOFF_0Y); 1530e3adcf8fSFrançois Tigeot P(OTILEOFF_1Y); 1531e3adcf8fSFrançois Tigeot P(OTILEOFF_0U); 1532e3adcf8fSFrançois Tigeot P(OTILEOFF_0V); 1533e3adcf8fSFrançois Tigeot P(OTILEOFF_1U); 1534e3adcf8fSFrançois Tigeot P(OTILEOFF_1V); 1535e3adcf8fSFrançois Tigeot P(FASTHSCALE); 1536e3adcf8fSFrançois Tigeot P(UVSCALEV); 1537e3adcf8fSFrançois Tigeot #undef P 1538e3adcf8fSFrançois Tigeot } 15393f2f609dSFrançois Tigeot #endif 1540