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" 3371f41f3eSFrançois Tigeot #include "intel_frontbuffer.h" 34e3adcf8fSFrançois Tigeot 35e3adcf8fSFrançois Tigeot /* Limits for overlay size. According to intel doc, the real limits are: 36e3adcf8fSFrançois Tigeot * Y width: 4095, UV width (planar): 2047, Y height: 2047, 37e3adcf8fSFrançois Tigeot * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use 38e3adcf8fSFrançois Tigeot * the mininum of both. */ 39e3adcf8fSFrançois Tigeot #define IMAGE_MAX_WIDTH 2048 40e3adcf8fSFrançois Tigeot #define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */ 41e3adcf8fSFrançois Tigeot /* on 830 and 845 these large limits result in the card hanging */ 42e3adcf8fSFrançois Tigeot #define IMAGE_MAX_WIDTH_LEGACY 1024 43e3adcf8fSFrançois Tigeot #define IMAGE_MAX_HEIGHT_LEGACY 1088 44e3adcf8fSFrançois Tigeot 45e3adcf8fSFrançois Tigeot /* overlay register definitions */ 46e3adcf8fSFrançois Tigeot /* OCMD register */ 47e3adcf8fSFrançois Tigeot #define OCMD_TILED_SURFACE (0x1<<19) 48e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_MASK (0x3<<17) 49e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_MODE (0x3<<17) 50e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_HORIZONTAL (0x1<<17) 51e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_VERTICAL (0x2<<17) 52e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_BOTH (0x3<<17) 53e3adcf8fSFrançois Tigeot #define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */ 54e3adcf8fSFrançois Tigeot #define OCMD_UV_SWAP (0x1<<14) /* YVYU */ 55e3adcf8fSFrançois Tigeot #define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */ 56e3adcf8fSFrançois Tigeot #define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */ 57e3adcf8fSFrançois Tigeot #define OCMD_SOURCE_FORMAT_MASK (0xf<<10) 58e3adcf8fSFrançois Tigeot #define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */ 59e3adcf8fSFrançois Tigeot #define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */ 60e3adcf8fSFrançois Tigeot #define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */ 61e3adcf8fSFrançois Tigeot #define OCMD_YUV_422_PACKED (0x8<<10) 62e3adcf8fSFrançois Tigeot #define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */ 63e3adcf8fSFrançois Tigeot #define OCMD_YUV_420_PLANAR (0xc<<10) 64e3adcf8fSFrançois Tigeot #define OCMD_YUV_422_PLANAR (0xd<<10) 65e3adcf8fSFrançois Tigeot #define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */ 66e3adcf8fSFrançois Tigeot #define OCMD_TVSYNCFLIP_PARITY (0x1<<9) 67e3adcf8fSFrançois Tigeot #define OCMD_TVSYNCFLIP_ENABLE (0x1<<7) 68e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_MASK (0x1<<5) 69e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_FRAME (0x0<<5) 70e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_FIELD (0x1<<5) 71e3adcf8fSFrançois Tigeot #define OCMD_TEST_MODE (0x1<<4) 72e3adcf8fSFrançois Tigeot #define OCMD_BUFFER_SELECT (0x3<<2) 73e3adcf8fSFrançois Tigeot #define OCMD_BUFFER0 (0x0<<2) 74e3adcf8fSFrançois Tigeot #define OCMD_BUFFER1 (0x1<<2) 75e3adcf8fSFrançois Tigeot #define OCMD_FIELD_SELECT (0x1<<2) 76e3adcf8fSFrançois Tigeot #define OCMD_FIELD0 (0x0<<1) 77e3adcf8fSFrançois Tigeot #define OCMD_FIELD1 (0x1<<1) 78e3adcf8fSFrançois Tigeot #define OCMD_ENABLE (0x1<<0) 79e3adcf8fSFrançois Tigeot 80e3adcf8fSFrançois Tigeot /* OCONFIG register */ 81e3adcf8fSFrançois Tigeot #define OCONF_PIPE_MASK (0x1<<18) 82e3adcf8fSFrançois Tigeot #define OCONF_PIPE_A (0x0<<18) 83e3adcf8fSFrançois Tigeot #define OCONF_PIPE_B (0x1<<18) 84e3adcf8fSFrançois Tigeot #define OCONF_GAMMA2_ENABLE (0x1<<16) 85e3adcf8fSFrançois Tigeot #define OCONF_CSC_MODE_BT601 (0x0<<5) 86e3adcf8fSFrançois Tigeot #define OCONF_CSC_MODE_BT709 (0x1<<5) 87e3adcf8fSFrançois Tigeot #define OCONF_CSC_BYPASS (0x1<<4) 88e3adcf8fSFrançois Tigeot #define OCONF_CC_OUT_8BIT (0x1<<3) 89e3adcf8fSFrançois Tigeot #define OCONF_TEST_MODE (0x1<<2) 90e3adcf8fSFrançois Tigeot #define OCONF_THREE_LINE_BUFFER (0x1<<0) 91e3adcf8fSFrançois Tigeot #define OCONF_TWO_LINE_BUFFER (0x0<<0) 92e3adcf8fSFrançois Tigeot 93e3adcf8fSFrançois Tigeot /* DCLRKM (dst-key) register */ 94e3adcf8fSFrançois Tigeot #define DST_KEY_ENABLE (0x1<<31) 95e3adcf8fSFrançois Tigeot #define CLK_RGB24_MASK 0x0 96e3adcf8fSFrançois Tigeot #define CLK_RGB16_MASK 0x070307 97e3adcf8fSFrançois Tigeot #define CLK_RGB15_MASK 0x070707 98e3adcf8fSFrançois Tigeot #define CLK_RGB8I_MASK 0xffffff 99e3adcf8fSFrançois Tigeot 100e3adcf8fSFrançois Tigeot #define RGB16_TO_COLORKEY(c) \ 101e3adcf8fSFrançois Tigeot (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) 102e3adcf8fSFrançois Tigeot #define RGB15_TO_COLORKEY(c) \ 103e3adcf8fSFrançois Tigeot (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3)) 104e3adcf8fSFrançois Tigeot 105e3adcf8fSFrançois Tigeot /* overlay flip addr flag */ 106e3adcf8fSFrançois Tigeot #define OFC_UPDATE 0x1 107e3adcf8fSFrançois Tigeot 108e3adcf8fSFrançois Tigeot /* polyphase filter coefficients */ 109e3adcf8fSFrançois Tigeot #define N_HORIZ_Y_TAPS 5 110e3adcf8fSFrançois Tigeot #define N_VERT_Y_TAPS 3 111e3adcf8fSFrançois Tigeot #define N_HORIZ_UV_TAPS 3 112e3adcf8fSFrançois Tigeot #define N_VERT_UV_TAPS 3 113e3adcf8fSFrançois Tigeot #define N_PHASES 17 114e3adcf8fSFrançois Tigeot #define MAX_TAPS 5 115e3adcf8fSFrançois Tigeot 116e3adcf8fSFrançois Tigeot /* memory bufferd overlay registers */ 117e3adcf8fSFrançois Tigeot struct overlay_registers { 118e3adcf8fSFrançois Tigeot u32 OBUF_0Y; 119e3adcf8fSFrançois Tigeot u32 OBUF_1Y; 120e3adcf8fSFrançois Tigeot u32 OBUF_0U; 121e3adcf8fSFrançois Tigeot u32 OBUF_0V; 122e3adcf8fSFrançois Tigeot u32 OBUF_1U; 123e3adcf8fSFrançois Tigeot u32 OBUF_1V; 124e3adcf8fSFrançois Tigeot u32 OSTRIDE; 125e3adcf8fSFrançois Tigeot u32 YRGB_VPH; 126e3adcf8fSFrançois Tigeot u32 UV_VPH; 127e3adcf8fSFrançois Tigeot u32 HORZ_PH; 128e3adcf8fSFrançois Tigeot u32 INIT_PHS; 129e3adcf8fSFrançois Tigeot u32 DWINPOS; 130e3adcf8fSFrançois Tigeot u32 DWINSZ; 131e3adcf8fSFrançois Tigeot u32 SWIDTH; 132e3adcf8fSFrançois Tigeot u32 SWIDTHSW; 133e3adcf8fSFrançois Tigeot u32 SHEIGHT; 134e3adcf8fSFrançois Tigeot u32 YRGBSCALE; 135e3adcf8fSFrançois Tigeot u32 UVSCALE; 136e3adcf8fSFrançois Tigeot u32 OCLRC0; 137e3adcf8fSFrançois Tigeot u32 OCLRC1; 138e3adcf8fSFrançois Tigeot u32 DCLRKV; 139e3adcf8fSFrançois Tigeot u32 DCLRKM; 140e3adcf8fSFrançois Tigeot u32 SCLRKVH; 141e3adcf8fSFrançois Tigeot u32 SCLRKVL; 142e3adcf8fSFrançois Tigeot u32 SCLRKEN; 143e3adcf8fSFrançois Tigeot u32 OCONFIG; 144e3adcf8fSFrançois Tigeot u32 OCMD; 145e3adcf8fSFrançois Tigeot u32 RESERVED1; /* 0x6C */ 146e3adcf8fSFrançois Tigeot u32 OSTART_0Y; 147e3adcf8fSFrançois Tigeot u32 OSTART_1Y; 148e3adcf8fSFrançois Tigeot u32 OSTART_0U; 149e3adcf8fSFrançois Tigeot u32 OSTART_0V; 150e3adcf8fSFrançois Tigeot u32 OSTART_1U; 151e3adcf8fSFrançois Tigeot u32 OSTART_1V; 152e3adcf8fSFrançois Tigeot u32 OTILEOFF_0Y; 153e3adcf8fSFrançois Tigeot u32 OTILEOFF_1Y; 154e3adcf8fSFrançois Tigeot u32 OTILEOFF_0U; 155e3adcf8fSFrançois Tigeot u32 OTILEOFF_0V; 156e3adcf8fSFrançois Tigeot u32 OTILEOFF_1U; 157e3adcf8fSFrançois Tigeot u32 OTILEOFF_1V; 158e3adcf8fSFrançois Tigeot u32 FASTHSCALE; /* 0xA0 */ 159e3adcf8fSFrançois Tigeot u32 UVSCALEV; /* 0xA4 */ 160e3adcf8fSFrançois Tigeot u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */ 161e3adcf8fSFrançois Tigeot u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */ 162e3adcf8fSFrançois Tigeot u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES]; 163e3adcf8fSFrançois Tigeot u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */ 164e3adcf8fSFrançois Tigeot u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES]; 165e3adcf8fSFrançois Tigeot u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */ 166e3adcf8fSFrançois Tigeot u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES]; 167e3adcf8fSFrançois Tigeot u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */ 168e3adcf8fSFrançois Tigeot u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; 169e3adcf8fSFrançois Tigeot }; 170e3adcf8fSFrançois Tigeot 171e3adcf8fSFrançois Tigeot struct intel_overlay { 1721487f786SFrançois Tigeot struct drm_i915_private *i915; 173e3adcf8fSFrançois Tigeot struct intel_crtc *crtc; 174*1e12ee3bSFrançois Tigeot struct i915_vma *vma; 175*1e12ee3bSFrançois Tigeot struct i915_vma *old_vma; 17619c468b4SFrançois Tigeot bool active; 17719c468b4SFrançois Tigeot bool pfit_active; 178e3adcf8fSFrançois Tigeot u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ 17919c468b4SFrançois Tigeot u32 color_key:24; 18019c468b4SFrançois Tigeot u32 color_key_enabled:1; 181e3adcf8fSFrançois Tigeot u32 brightness, contrast, saturation; 182e3adcf8fSFrançois Tigeot u32 old_xscale, old_yscale; 183e3adcf8fSFrançois Tigeot /* register access */ 184e3adcf8fSFrançois Tigeot u32 flip_addr; 185e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *reg_bo; 186e3adcf8fSFrançois Tigeot /* flip handling */ 18771f41f3eSFrançois Tigeot struct i915_gem_active last_flip; 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 { 1931487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 194e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 195e3adcf8fSFrançois Tigeot 1961487f786SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) 197ba55f2f5SFrançois Tigeot regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr; 198e3440f96SFrançois Tigeot else 199*1e12ee3bSFrançois Tigeot regs = io_mapping_map_wc(&dev_priv->ggtt.mappable, 2001487f786SFrançois Tigeot overlay->flip_addr, 2011487f786SFrançois Tigeot PAGE_SIZE); 202e3440f96SFrançois Tigeot 203e3440f96SFrançois Tigeot return regs; 204e3adcf8fSFrançois Tigeot } 205e3adcf8fSFrançois Tigeot 206e3adcf8fSFrançois Tigeot static void intel_overlay_unmap_regs(struct intel_overlay *overlay, 207e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 208e3adcf8fSFrançois Tigeot { 2091487f786SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915)) 210bf017597SFrançois Tigeot io_mapping_unmap(regs); 211e3adcf8fSFrançois Tigeot } 212e3adcf8fSFrançois Tigeot 21371f41f3eSFrançois Tigeot static void intel_overlay_submit_request(struct intel_overlay *overlay, 21471f41f3eSFrançois Tigeot struct drm_i915_gem_request *req, 21571f41f3eSFrançois Tigeot i915_gem_retire_fn retire) 21671f41f3eSFrançois Tigeot { 21771f41f3eSFrançois Tigeot GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip, 21871f41f3eSFrançois Tigeot &overlay->i915->drm.struct_mutex)); 21971f41f3eSFrançois Tigeot overlay->last_flip.retire = retire; 22071f41f3eSFrançois Tigeot i915_gem_active_set(&overlay->last_flip, req); 22171f41f3eSFrançois Tigeot i915_add_request(req); 22271f41f3eSFrançois Tigeot } 22371f41f3eSFrançois Tigeot 224e3adcf8fSFrançois Tigeot static int intel_overlay_do_wait_request(struct intel_overlay *overlay, 225a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req, 22671f41f3eSFrançois Tigeot i915_gem_retire_fn retire) 227e3adcf8fSFrançois Tigeot { 22871f41f3eSFrançois Tigeot intel_overlay_submit_request(overlay, req, retire); 22971f41f3eSFrançois Tigeot return i915_gem_active_retire(&overlay->last_flip, 23071f41f3eSFrançois Tigeot &overlay->i915->drm.struct_mutex); 23171f41f3eSFrançois Tigeot } 232e3adcf8fSFrançois Tigeot 23371f41f3eSFrançois Tigeot static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay) 23471f41f3eSFrançois Tigeot { 23571f41f3eSFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 236*1e12ee3bSFrançois Tigeot struct intel_engine_cs *engine = dev_priv->engine[RCS]; 237f192107fSFrançois Tigeot 23871f41f3eSFrançois Tigeot return i915_gem_request_alloc(engine, dev_priv->kernel_context); 239e3adcf8fSFrançois Tigeot } 240e3adcf8fSFrançois Tigeot 241e3adcf8fSFrançois Tigeot /* overlay needs to be disable in OCMD reg */ 242e3adcf8fSFrançois Tigeot static int intel_overlay_on(struct intel_overlay *overlay) 243e3adcf8fSFrançois Tigeot { 2441487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 245a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 24671f41f3eSFrançois Tigeot struct intel_ring *ring; 247e3adcf8fSFrançois Tigeot int ret; 248e3adcf8fSFrançois Tigeot 24919c468b4SFrançois Tigeot WARN_ON(overlay->active); 2501487f786SFrançois Tigeot WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE)); 251e3adcf8fSFrançois Tigeot 25271f41f3eSFrançois Tigeot req = alloc_request(overlay); 253c0e85e96SFrançois Tigeot if (IS_ERR(req)) 254c0e85e96SFrançois Tigeot return PTR_ERR(req); 255f192107fSFrançois Tigeot 256a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 4); 257a05eeebfSFrançois Tigeot if (ret) { 2588621f407SFrançois Tigeot i915_add_request_no_flush(req); 259a05eeebfSFrançois Tigeot return ret; 260a05eeebfSFrançois Tigeot } 261a05eeebfSFrançois Tigeot 26219c468b4SFrançois Tigeot overlay->active = true; 26319c468b4SFrançois Tigeot 26471f41f3eSFrançois Tigeot ring = req->ring; 26571f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON); 26671f41f3eSFrançois Tigeot intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE); 26771f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 26871f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 26971f41f3eSFrançois Tigeot intel_ring_advance(ring); 270f192107fSFrançois Tigeot 271a05eeebfSFrançois Tigeot return intel_overlay_do_wait_request(overlay, req, NULL); 272e3adcf8fSFrançois Tigeot } 273e3adcf8fSFrançois Tigeot 274e3adcf8fSFrançois Tigeot /* overlay needs to be enabled in OCMD reg */ 275e3adcf8fSFrançois Tigeot static int intel_overlay_continue(struct intel_overlay *overlay, 276e3adcf8fSFrançois Tigeot bool load_polyphase_filter) 277e3adcf8fSFrançois Tigeot { 2781487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 279a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 28071f41f3eSFrançois Tigeot struct intel_ring *ring; 281e3adcf8fSFrançois Tigeot u32 flip_addr = overlay->flip_addr; 282e3adcf8fSFrançois Tigeot u32 tmp; 283e3adcf8fSFrançois Tigeot int ret; 284e3adcf8fSFrançois Tigeot 28519c468b4SFrançois Tigeot WARN_ON(!overlay->active); 286e3adcf8fSFrançois Tigeot 287e3adcf8fSFrançois Tigeot if (load_polyphase_filter) 288e3adcf8fSFrançois Tigeot flip_addr |= OFC_UPDATE; 289e3adcf8fSFrançois Tigeot 290e3adcf8fSFrançois Tigeot /* check for underruns */ 291e3adcf8fSFrançois Tigeot tmp = I915_READ(DOVSTA); 292e3adcf8fSFrançois Tigeot if (tmp & (1 << 17)) 293e3adcf8fSFrançois Tigeot DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); 294e3adcf8fSFrançois Tigeot 29571f41f3eSFrançois Tigeot req = alloc_request(overlay); 296c0e85e96SFrançois Tigeot if (IS_ERR(req)) 297c0e85e96SFrançois Tigeot return PTR_ERR(req); 298e3adcf8fSFrançois Tigeot 299a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 2); 300a05eeebfSFrançois Tigeot if (ret) { 3018621f407SFrançois Tigeot i915_add_request_no_flush(req); 302a05eeebfSFrançois Tigeot return ret; 303a05eeebfSFrançois Tigeot } 304a05eeebfSFrançois Tigeot 30571f41f3eSFrançois Tigeot ring = req->ring; 30671f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 30771f41f3eSFrançois Tigeot intel_ring_emit(ring, flip_addr); 30871f41f3eSFrançois Tigeot intel_ring_advance(ring); 309e3adcf8fSFrançois Tigeot 31071f41f3eSFrançois Tigeot intel_overlay_submit_request(overlay, req, NULL); 311a05eeebfSFrançois Tigeot 312a05eeebfSFrançois Tigeot return 0; 313e3adcf8fSFrançois Tigeot } 314e3adcf8fSFrançois Tigeot 31571f41f3eSFrançois Tigeot static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active, 31671f41f3eSFrançois Tigeot struct drm_i915_gem_request *req) 317e3adcf8fSFrançois Tigeot { 31871f41f3eSFrançois Tigeot struct intel_overlay *overlay = 31971f41f3eSFrançois Tigeot container_of(active, typeof(*overlay), last_flip); 320*1e12ee3bSFrançois Tigeot struct i915_vma *vma; 321e3adcf8fSFrançois Tigeot 322*1e12ee3bSFrançois Tigeot vma = fetch_and_zero(&overlay->old_vma); 323*1e12ee3bSFrançois Tigeot if (WARN_ON(!vma)) 324*1e12ee3bSFrançois Tigeot return; 325*1e12ee3bSFrançois Tigeot 326*1e12ee3bSFrançois Tigeot i915_gem_track_fb(vma->obj, NULL, 32771f41f3eSFrançois Tigeot INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe)); 32871f41f3eSFrançois Tigeot 329*1e12ee3bSFrançois Tigeot i915_gem_object_unpin_from_display_plane(vma); 330*1e12ee3bSFrançois Tigeot i915_vma_put(vma); 331e3adcf8fSFrançois Tigeot } 332e3adcf8fSFrançois Tigeot 33371f41f3eSFrançois Tigeot static void intel_overlay_off_tail(struct i915_gem_active *active, 33471f41f3eSFrançois Tigeot struct drm_i915_gem_request *req) 335e3adcf8fSFrançois Tigeot { 33671f41f3eSFrançois Tigeot struct intel_overlay *overlay = 33771f41f3eSFrançois Tigeot container_of(active, typeof(*overlay), last_flip); 338*1e12ee3bSFrançois Tigeot struct i915_vma *vma; 339e3adcf8fSFrançois Tigeot 340e3adcf8fSFrançois Tigeot /* never have the overlay hw on without showing a frame */ 341*1e12ee3bSFrançois Tigeot vma = fetch_and_zero(&overlay->vma); 342*1e12ee3bSFrançois Tigeot if (WARN_ON(!vma)) 34319c468b4SFrançois Tigeot return; 344e3adcf8fSFrançois Tigeot 345*1e12ee3bSFrançois Tigeot i915_gem_object_unpin_from_display_plane(vma); 346*1e12ee3bSFrançois Tigeot i915_vma_put(vma); 347e3adcf8fSFrançois Tigeot 348e3adcf8fSFrançois Tigeot overlay->crtc->overlay = NULL; 349e3adcf8fSFrançois Tigeot overlay->crtc = NULL; 35019c468b4SFrançois Tigeot overlay->active = false; 351e3adcf8fSFrançois Tigeot } 352e3adcf8fSFrançois Tigeot 353e3adcf8fSFrançois Tigeot /* overlay needs to be disabled in OCMD reg */ 354e3adcf8fSFrançois Tigeot static int intel_overlay_off(struct intel_overlay *overlay) 355e3adcf8fSFrançois Tigeot { 3561487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 357a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 35871f41f3eSFrançois Tigeot struct intel_ring *ring; 359e3adcf8fSFrançois Tigeot u32 flip_addr = overlay->flip_addr; 360e3adcf8fSFrançois Tigeot int ret; 361e3adcf8fSFrançois Tigeot 36219c468b4SFrançois Tigeot WARN_ON(!overlay->active); 363e3adcf8fSFrançois Tigeot 364e3adcf8fSFrançois Tigeot /* According to intel docs the overlay hw may hang (when switching 365e3adcf8fSFrançois Tigeot * off) without loading the filter coeffs. It is however unclear whether 366e3adcf8fSFrançois Tigeot * this applies to the disabling of the overlay or to the switching off 367e3adcf8fSFrançois Tigeot * of the hw. Do it in both cases */ 368e3adcf8fSFrançois Tigeot flip_addr |= OFC_UPDATE; 369e3adcf8fSFrançois Tigeot 37071f41f3eSFrançois Tigeot req = alloc_request(overlay); 371c0e85e96SFrançois Tigeot if (IS_ERR(req)) 372c0e85e96SFrançois Tigeot return PTR_ERR(req); 373e3adcf8fSFrançois Tigeot 374a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 6); 375a05eeebfSFrançois Tigeot if (ret) { 3768621f407SFrançois Tigeot i915_add_request_no_flush(req); 377a05eeebfSFrançois Tigeot return ret; 378a05eeebfSFrançois Tigeot } 379a05eeebfSFrançois Tigeot 38071f41f3eSFrançois Tigeot ring = req->ring; 381f192107fSFrançois Tigeot /* wait for overlay to go idle */ 38271f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 38371f41f3eSFrançois Tigeot intel_ring_emit(ring, flip_addr); 38471f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 385f192107fSFrançois Tigeot /* turn overlay off */ 3861487f786SFrançois Tigeot if (IS_I830(dev_priv)) { 38719df918dSFrançois Tigeot /* Workaround: Don't disable the overlay fully, since otherwise 38819df918dSFrançois Tigeot * it dies on the next OVERLAY_ON cmd. */ 38971f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 39071f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 39171f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 39219df918dSFrançois Tigeot } else { 39371f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF); 39471f41f3eSFrançois Tigeot intel_ring_emit(ring, flip_addr); 39571f41f3eSFrançois Tigeot intel_ring_emit(ring, 3968621f407SFrançois Tigeot MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 39719df918dSFrançois Tigeot } 39871f41f3eSFrançois Tigeot intel_ring_advance(ring); 399f192107fSFrançois Tigeot 40071f41f3eSFrançois Tigeot return intel_overlay_do_wait_request(overlay, req, 40171f41f3eSFrançois Tigeot intel_overlay_off_tail); 402e3adcf8fSFrançois Tigeot } 403e3adcf8fSFrançois Tigeot 404e3adcf8fSFrançois Tigeot /* recover from an interruption due to a signal 405e3adcf8fSFrançois Tigeot * We have to be careful not to repeat work forever an make forward progess. */ 406e3adcf8fSFrançois Tigeot static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) 407e3adcf8fSFrançois Tigeot { 40871f41f3eSFrançois Tigeot return i915_gem_active_retire(&overlay->last_flip, 40971f41f3eSFrançois Tigeot &overlay->i915->drm.struct_mutex); 410e3adcf8fSFrançois Tigeot } 411e3adcf8fSFrançois Tigeot 412e3adcf8fSFrançois Tigeot /* Wait for pending overlay flip and release old frame. 413e3adcf8fSFrançois Tigeot * Needs to be called before the overlay register are changed 414e3adcf8fSFrançois Tigeot * via intel_overlay_(un)map_regs 415e3adcf8fSFrançois Tigeot */ 416e3adcf8fSFrançois Tigeot static int intel_overlay_release_old_vid(struct intel_overlay *overlay) 417e3adcf8fSFrançois Tigeot { 4181487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 419e3adcf8fSFrançois Tigeot int ret; 420e3adcf8fSFrançois Tigeot 421303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex); 4222c9916cdSFrançois Tigeot 423e3adcf8fSFrançois Tigeot /* Only wait if there is actually an old frame to release to 424e3adcf8fSFrançois Tigeot * guarantee forward progress. 425e3adcf8fSFrançois Tigeot */ 426*1e12ee3bSFrançois Tigeot if (!overlay->old_vma) 427e3adcf8fSFrançois Tigeot return 0; 428e3adcf8fSFrançois Tigeot 429e3adcf8fSFrançois Tigeot if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { 430e3adcf8fSFrançois Tigeot /* synchronous slowpath */ 431a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 43271f41f3eSFrançois Tigeot struct intel_ring *ring; 433a05eeebfSFrançois Tigeot 43471f41f3eSFrançois Tigeot req = alloc_request(overlay); 435c0e85e96SFrançois Tigeot if (IS_ERR(req)) 436c0e85e96SFrançois Tigeot return PTR_ERR(req); 437e3adcf8fSFrançois Tigeot 438a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 2); 439a05eeebfSFrançois Tigeot if (ret) { 4408621f407SFrançois Tigeot i915_add_request_no_flush(req); 441a05eeebfSFrançois Tigeot return ret; 442a05eeebfSFrançois Tigeot } 443a05eeebfSFrançois Tigeot 44471f41f3eSFrançois Tigeot ring = req->ring; 44571f41f3eSFrançois Tigeot intel_ring_emit(ring, 4468621f407SFrançois Tigeot MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 44771f41f3eSFrançois Tigeot intel_ring_emit(ring, MI_NOOP); 44871f41f3eSFrançois Tigeot intel_ring_advance(ring); 449e3adcf8fSFrançois Tigeot 450a05eeebfSFrançois Tigeot ret = intel_overlay_do_wait_request(overlay, req, 451e3adcf8fSFrançois Tigeot intel_overlay_release_old_vid_tail); 452e3adcf8fSFrançois Tigeot if (ret) 453e3adcf8fSFrançois Tigeot return ret; 45471f41f3eSFrançois Tigeot } else 45571f41f3eSFrançois Tigeot intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL); 456e3adcf8fSFrançois Tigeot 457e3adcf8fSFrançois Tigeot return 0; 458e3adcf8fSFrançois Tigeot } 459e3adcf8fSFrançois Tigeot 4602c9916cdSFrançois Tigeot void intel_overlay_reset(struct drm_i915_private *dev_priv) 4612c9916cdSFrançois Tigeot { 4622c9916cdSFrançois Tigeot struct intel_overlay *overlay = dev_priv->overlay; 4632c9916cdSFrançois Tigeot 4642c9916cdSFrançois Tigeot if (!overlay) 4652c9916cdSFrançois Tigeot return; 4662c9916cdSFrançois Tigeot 4672c9916cdSFrançois Tigeot intel_overlay_release_old_vid(overlay); 4682c9916cdSFrançois Tigeot 4692c9916cdSFrançois Tigeot overlay->old_xscale = 0; 4702c9916cdSFrançois Tigeot overlay->old_yscale = 0; 4712c9916cdSFrançois Tigeot overlay->crtc = NULL; 4722c9916cdSFrançois Tigeot overlay->active = false; 4732c9916cdSFrançois Tigeot } 4742c9916cdSFrançois Tigeot 475e3adcf8fSFrançois Tigeot struct put_image_params { 476e3adcf8fSFrançois Tigeot int format; 477e3adcf8fSFrançois Tigeot short dst_x; 478e3adcf8fSFrançois Tigeot short dst_y; 479e3adcf8fSFrançois Tigeot short dst_w; 480e3adcf8fSFrançois Tigeot short dst_h; 481e3adcf8fSFrançois Tigeot short src_w; 482e3adcf8fSFrançois Tigeot short src_scan_h; 483e3adcf8fSFrançois Tigeot short src_scan_w; 484e3adcf8fSFrançois Tigeot short src_h; 485e3adcf8fSFrançois Tigeot short stride_Y; 486e3adcf8fSFrançois Tigeot short stride_UV; 487e3adcf8fSFrançois Tigeot int offset_Y; 488e3adcf8fSFrançois Tigeot int offset_U; 489e3adcf8fSFrançois Tigeot int offset_V; 490e3adcf8fSFrançois Tigeot }; 491e3adcf8fSFrançois Tigeot 492e3adcf8fSFrançois Tigeot static int packed_depth_bytes(u32 format) 493e3adcf8fSFrançois Tigeot { 494e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 495e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 496e3adcf8fSFrançois Tigeot return 4; 497e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 498e3adcf8fSFrançois Tigeot /* return 6; not implemented */ 499e3adcf8fSFrançois Tigeot default: 500e3adcf8fSFrançois Tigeot return -EINVAL; 501e3adcf8fSFrançois Tigeot } 502e3adcf8fSFrançois Tigeot } 503e3adcf8fSFrançois Tigeot 504e3adcf8fSFrançois Tigeot static int packed_width_bytes(u32 format, short width) 505e3adcf8fSFrançois Tigeot { 506e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 507e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 508e3adcf8fSFrançois Tigeot return width << 1; 509e3adcf8fSFrançois Tigeot default: 510e3adcf8fSFrançois Tigeot return -EINVAL; 511e3adcf8fSFrançois Tigeot } 512e3adcf8fSFrançois Tigeot } 513e3adcf8fSFrançois Tigeot 514e3adcf8fSFrançois Tigeot static int uv_hsubsampling(u32 format) 515e3adcf8fSFrançois Tigeot { 516e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 517e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 518e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 519e3adcf8fSFrançois Tigeot return 2; 520e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 521e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 522e3adcf8fSFrançois Tigeot return 4; 523e3adcf8fSFrançois Tigeot default: 524e3adcf8fSFrançois Tigeot return -EINVAL; 525e3adcf8fSFrançois Tigeot } 526e3adcf8fSFrançois Tigeot } 527e3adcf8fSFrançois Tigeot 528e3adcf8fSFrançois Tigeot static int uv_vsubsampling(u32 format) 529e3adcf8fSFrançois Tigeot { 530e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 531e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 532e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 533e3adcf8fSFrançois Tigeot return 2; 534e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 535e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 536e3adcf8fSFrançois Tigeot return 1; 537e3adcf8fSFrançois Tigeot default: 538e3adcf8fSFrançois Tigeot return -EINVAL; 539e3adcf8fSFrançois Tigeot } 540e3adcf8fSFrançois Tigeot } 541e3adcf8fSFrançois Tigeot 5421487f786SFrançois Tigeot static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width) 543e3adcf8fSFrançois Tigeot { 544e3adcf8fSFrançois Tigeot u32 mask, shift, ret; 5451487f786SFrançois Tigeot if (IS_GEN2(dev_priv)) { 546e3adcf8fSFrançois Tigeot mask = 0x1f; 547e3adcf8fSFrançois Tigeot shift = 5; 548e3adcf8fSFrançois Tigeot } else { 549e3adcf8fSFrançois Tigeot mask = 0x3f; 550e3adcf8fSFrançois Tigeot shift = 6; 551e3adcf8fSFrançois Tigeot } 552e3adcf8fSFrançois Tigeot ret = ((offset + width + mask) >> shift) - (offset >> shift); 5531487f786SFrançois Tigeot if (!IS_GEN2(dev_priv)) 554e3adcf8fSFrançois Tigeot ret <<= 1; 555e3adcf8fSFrançois Tigeot ret -= 1; 556e3adcf8fSFrançois Tigeot return ret << 2; 557e3adcf8fSFrançois Tigeot } 558e3adcf8fSFrançois Tigeot 559e3adcf8fSFrançois Tigeot static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { 560e3adcf8fSFrançois Tigeot 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0, 561e3adcf8fSFrançois Tigeot 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440, 562e3adcf8fSFrançois Tigeot 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0, 563e3adcf8fSFrançois Tigeot 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380, 564e3adcf8fSFrançois Tigeot 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320, 565e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0, 566e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260, 567e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200, 568e3adcf8fSFrançois Tigeot 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0, 569e3adcf8fSFrançois Tigeot 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160, 570e3adcf8fSFrançois Tigeot 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120, 571e3adcf8fSFrançois Tigeot 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0, 572e3adcf8fSFrançois Tigeot 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0, 573e3adcf8fSFrançois Tigeot 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, 574e3adcf8fSFrançois Tigeot 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, 575e3adcf8fSFrançois Tigeot 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, 576e3adcf8fSFrançois Tigeot 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 577e3adcf8fSFrançois Tigeot }; 578e3adcf8fSFrançois Tigeot 579e3adcf8fSFrançois Tigeot static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { 580e3adcf8fSFrançois Tigeot 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, 581e3adcf8fSFrançois Tigeot 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, 582e3adcf8fSFrançois Tigeot 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880, 583e3adcf8fSFrançois Tigeot 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00, 584e3adcf8fSFrançois Tigeot 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0, 585e3adcf8fSFrançois Tigeot 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, 586e3adcf8fSFrançois Tigeot 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, 587e3adcf8fSFrançois Tigeot 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, 588e3adcf8fSFrançois Tigeot 0x3000, 0x0800, 0x3000 589e3adcf8fSFrançois Tigeot }; 590e3adcf8fSFrançois Tigeot 591e3440f96SFrançois Tigeot static void update_polyphase_filter(struct overlay_registers __iomem *regs) 592e3adcf8fSFrançois Tigeot { 593e3440f96SFrançois Tigeot memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs)); 594e3440f96SFrançois Tigeot memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs, 595e3440f96SFrançois Tigeot sizeof(uv_static_hcoeffs)); 596e3adcf8fSFrançois Tigeot } 597e3adcf8fSFrançois Tigeot 598e3adcf8fSFrançois Tigeot static bool update_scaling_factors(struct intel_overlay *overlay, 599e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs, 600e3adcf8fSFrançois Tigeot struct put_image_params *params) 601e3adcf8fSFrançois Tigeot { 602e3adcf8fSFrançois Tigeot /* fixed point with a 12 bit shift */ 603e3adcf8fSFrançois Tigeot u32 xscale, yscale, xscale_UV, yscale_UV; 604e3adcf8fSFrançois Tigeot #define FP_SHIFT 12 605e3adcf8fSFrançois Tigeot #define FRACT_MASK 0xfff 606e3adcf8fSFrançois Tigeot bool scale_changed = false; 607e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(params->format); 608e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(params->format); 609e3adcf8fSFrançois Tigeot 610e3adcf8fSFrançois Tigeot if (params->dst_w > 1) 611e3adcf8fSFrançois Tigeot xscale = ((params->src_scan_w - 1) << FP_SHIFT) 612e3adcf8fSFrançois Tigeot /(params->dst_w); 613e3adcf8fSFrançois Tigeot else 614e3adcf8fSFrançois Tigeot xscale = 1 << FP_SHIFT; 615e3adcf8fSFrançois Tigeot 616e3adcf8fSFrançois Tigeot if (params->dst_h > 1) 617e3adcf8fSFrançois Tigeot yscale = ((params->src_scan_h - 1) << FP_SHIFT) 618e3adcf8fSFrançois Tigeot /(params->dst_h); 619e3adcf8fSFrançois Tigeot else 620e3adcf8fSFrançois Tigeot yscale = 1 << FP_SHIFT; 621e3adcf8fSFrançois Tigeot 622e3adcf8fSFrançois Tigeot /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ 623e3adcf8fSFrançois Tigeot xscale_UV = xscale/uv_hscale; 624e3adcf8fSFrançois Tigeot yscale_UV = yscale/uv_vscale; 625e3adcf8fSFrançois Tigeot /* make the Y scale to UV scale ratio an exact multiply */ 626e3adcf8fSFrançois Tigeot xscale = xscale_UV * uv_hscale; 627e3adcf8fSFrançois Tigeot yscale = yscale_UV * uv_vscale; 628e3adcf8fSFrançois Tigeot /*} else { 629e3adcf8fSFrançois Tigeot xscale_UV = 0; 630e3adcf8fSFrançois Tigeot yscale_UV = 0; 631e3adcf8fSFrançois Tigeot }*/ 632e3adcf8fSFrançois Tigeot 633e3adcf8fSFrançois Tigeot if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) 634e3adcf8fSFrançois Tigeot scale_changed = true; 635e3adcf8fSFrançois Tigeot overlay->old_xscale = xscale; 636e3adcf8fSFrançois Tigeot overlay->old_yscale = yscale; 637e3adcf8fSFrançois Tigeot 638e3440f96SFrançois Tigeot iowrite32(((yscale & FRACT_MASK) << 20) | 639e3adcf8fSFrançois Tigeot ((xscale >> FP_SHIFT) << 16) | 640e3440f96SFrançois Tigeot ((xscale & FRACT_MASK) << 3), 641e3440f96SFrançois Tigeot ®s->YRGBSCALE); 642e3adcf8fSFrançois Tigeot 643e3440f96SFrançois Tigeot iowrite32(((yscale_UV & FRACT_MASK) << 20) | 644e3adcf8fSFrançois Tigeot ((xscale_UV >> FP_SHIFT) << 16) | 645e3440f96SFrançois Tigeot ((xscale_UV & FRACT_MASK) << 3), 646e3440f96SFrançois Tigeot ®s->UVSCALE); 647e3adcf8fSFrançois Tigeot 648e3440f96SFrançois Tigeot iowrite32((((yscale >> FP_SHIFT) << 16) | 649e3440f96SFrançois Tigeot ((yscale_UV >> FP_SHIFT) << 0)), 650e3440f96SFrançois Tigeot ®s->UVSCALEV); 651e3adcf8fSFrançois Tigeot 652e3adcf8fSFrançois Tigeot if (scale_changed) 653e3adcf8fSFrançois Tigeot update_polyphase_filter(regs); 654e3adcf8fSFrançois Tigeot 655e3adcf8fSFrançois Tigeot return scale_changed; 656e3adcf8fSFrançois Tigeot } 657e3adcf8fSFrançois Tigeot 658e3adcf8fSFrançois Tigeot static void update_colorkey(struct intel_overlay *overlay, 659e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 660e3adcf8fSFrançois Tigeot { 661e3adcf8fSFrançois Tigeot u32 key = overlay->color_key; 66219c468b4SFrançois Tigeot u32 flags; 66319c468b4SFrançois Tigeot 66419c468b4SFrançois Tigeot flags = 0; 66519c468b4SFrançois Tigeot if (overlay->color_key_enabled) 66619c468b4SFrançois Tigeot flags |= DST_KEY_ENABLE; 667e3adcf8fSFrançois Tigeot 668ba55f2f5SFrançois Tigeot switch (overlay->crtc->base.primary->fb->bits_per_pixel) { 669e3adcf8fSFrançois Tigeot case 8: 67019c468b4SFrançois Tigeot key = 0; 67119c468b4SFrançois Tigeot flags |= CLK_RGB8I_MASK; 672e3adcf8fSFrançois Tigeot break; 673e3adcf8fSFrançois Tigeot 674e3adcf8fSFrançois Tigeot case 16: 675ba55f2f5SFrançois Tigeot if (overlay->crtc->base.primary->fb->depth == 15) { 67619c468b4SFrançois Tigeot key = RGB15_TO_COLORKEY(key); 67719c468b4SFrançois Tigeot flags |= CLK_RGB15_MASK; 678e3adcf8fSFrançois Tigeot } else { 67919c468b4SFrançois Tigeot key = RGB16_TO_COLORKEY(key); 68019c468b4SFrançois Tigeot flags |= CLK_RGB16_MASK; 681e3adcf8fSFrançois Tigeot } 682e3adcf8fSFrançois Tigeot break; 683e3adcf8fSFrançois Tigeot 684e3adcf8fSFrançois Tigeot case 24: 685e3adcf8fSFrançois Tigeot case 32: 68619c468b4SFrançois Tigeot flags |= CLK_RGB24_MASK; 687e3adcf8fSFrançois Tigeot break; 688e3adcf8fSFrançois Tigeot } 68919c468b4SFrançois Tigeot 69019c468b4SFrançois Tigeot iowrite32(key, ®s->DCLRKV); 69119c468b4SFrançois Tigeot iowrite32(flags, ®s->DCLRKM); 692e3adcf8fSFrançois Tigeot } 693e3adcf8fSFrançois Tigeot 694e3adcf8fSFrançois Tigeot static u32 overlay_cmd_reg(struct put_image_params *params) 695e3adcf8fSFrançois Tigeot { 696e3adcf8fSFrançois Tigeot u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0; 697e3adcf8fSFrançois Tigeot 698e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PLANAR) { 699e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_DEPTH_MASK) { 700e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 701e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_422_PLANAR; 702e3adcf8fSFrançois Tigeot break; 703e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 704e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_420_PLANAR; 705e3adcf8fSFrançois Tigeot break; 706e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 707e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 708e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_410_PLANAR; 709e3adcf8fSFrançois Tigeot break; 710e3adcf8fSFrançois Tigeot } 711e3adcf8fSFrançois Tigeot } else { /* YUV packed */ 712e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_DEPTH_MASK) { 713e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 714e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_422_PACKED; 715e3adcf8fSFrançois Tigeot break; 716e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 717e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_411_PACKED; 718e3adcf8fSFrançois Tigeot break; 719e3adcf8fSFrançois Tigeot } 720e3adcf8fSFrançois Tigeot 721e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_SWAP_MASK) { 722e3adcf8fSFrançois Tigeot case I915_OVERLAY_NO_SWAP: 723e3adcf8fSFrançois Tigeot break; 724e3adcf8fSFrançois Tigeot case I915_OVERLAY_UV_SWAP: 725e3adcf8fSFrançois Tigeot cmd |= OCMD_UV_SWAP; 726e3adcf8fSFrançois Tigeot break; 727e3adcf8fSFrançois Tigeot case I915_OVERLAY_Y_SWAP: 728e3adcf8fSFrançois Tigeot cmd |= OCMD_Y_SWAP; 729e3adcf8fSFrançois Tigeot break; 730e3adcf8fSFrançois Tigeot case I915_OVERLAY_Y_AND_UV_SWAP: 731e3adcf8fSFrançois Tigeot cmd |= OCMD_Y_AND_UV_SWAP; 732e3adcf8fSFrançois Tigeot break; 733e3adcf8fSFrançois Tigeot } 734e3adcf8fSFrançois Tigeot } 735e3adcf8fSFrançois Tigeot 736e3adcf8fSFrançois Tigeot return cmd; 737e3adcf8fSFrançois Tigeot } 738e3adcf8fSFrançois Tigeot 739e3adcf8fSFrançois Tigeot static int intel_overlay_do_put_image(struct intel_overlay *overlay, 740e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo, 741e3adcf8fSFrançois Tigeot struct put_image_params *params) 742e3adcf8fSFrançois Tigeot { 743e3adcf8fSFrançois Tigeot int ret, tmp_width; 744e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 745e3adcf8fSFrançois Tigeot bool scale_changed = false; 7461487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 747e3440f96SFrançois Tigeot u32 swidth, swidthsw, sheight, ostride; 74824edb884SFrançois Tigeot enum i915_pipe pipe = overlay->crtc->pipe; 749*1e12ee3bSFrançois Tigeot struct i915_vma *vma; 750e3adcf8fSFrançois Tigeot 751303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex); 752303bf270SFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex)); 753e3adcf8fSFrançois Tigeot 754e3adcf8fSFrançois Tigeot ret = intel_overlay_release_old_vid(overlay); 755e3adcf8fSFrançois Tigeot if (ret != 0) 756e3adcf8fSFrançois Tigeot return ret; 757e3adcf8fSFrançois Tigeot 758*1e12ee3bSFrançois Tigeot vma = i915_gem_object_pin_to_display_plane(new_bo, 0, 759477eb7f9SFrançois Tigeot &i915_ggtt_view_normal); 760*1e12ee3bSFrançois Tigeot if (IS_ERR(vma)) 761*1e12ee3bSFrançois Tigeot return PTR_ERR(vma); 762e3adcf8fSFrançois Tigeot 763*1e12ee3bSFrançois Tigeot ret = i915_vma_put_fence(vma); 764e3adcf8fSFrançois Tigeot if (ret) 765e3adcf8fSFrançois Tigeot goto out_unpin; 766e3adcf8fSFrançois Tigeot 767e3adcf8fSFrançois Tigeot if (!overlay->active) { 768e3440f96SFrançois Tigeot u32 oconfig; 769e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 770e3adcf8fSFrançois Tigeot if (!regs) { 771e3adcf8fSFrançois Tigeot ret = -ENOMEM; 772e3adcf8fSFrançois Tigeot goto out_unpin; 773e3adcf8fSFrançois Tigeot } 774e3440f96SFrançois Tigeot oconfig = OCONF_CC_OUT_8BIT; 7751487f786SFrançois Tigeot if (IS_GEN4(dev_priv)) 776e3440f96SFrançois Tigeot oconfig |= OCONF_CSC_MODE_BT709; 77724edb884SFrançois Tigeot oconfig |= pipe == 0 ? 778e3adcf8fSFrançois Tigeot OCONF_PIPE_A : OCONF_PIPE_B; 779e3440f96SFrançois Tigeot iowrite32(oconfig, ®s->OCONFIG); 780e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 781e3adcf8fSFrançois Tigeot 782e3adcf8fSFrançois Tigeot ret = intel_overlay_on(overlay); 783e3adcf8fSFrançois Tigeot if (ret != 0) 784e3adcf8fSFrançois Tigeot goto out_unpin; 785e3adcf8fSFrançois Tigeot } 786e3adcf8fSFrançois Tigeot 787e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 788e3adcf8fSFrançois Tigeot if (!regs) { 789e3adcf8fSFrançois Tigeot ret = -ENOMEM; 790e3adcf8fSFrançois Tigeot goto out_unpin; 791e3adcf8fSFrançois Tigeot } 792e3adcf8fSFrançois Tigeot 793e3440f96SFrançois Tigeot iowrite32((params->dst_y << 16) | params->dst_x, ®s->DWINPOS); 794e3440f96SFrançois Tigeot iowrite32((params->dst_h << 16) | params->dst_w, ®s->DWINSZ); 795e3adcf8fSFrançois Tigeot 796e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PACKED) 797e3adcf8fSFrançois Tigeot tmp_width = packed_width_bytes(params->format, params->src_w); 798e3adcf8fSFrançois Tigeot else 799e3adcf8fSFrançois Tigeot tmp_width = params->src_w; 800e3adcf8fSFrançois Tigeot 801e3440f96SFrançois Tigeot swidth = params->src_w; 8021487f786SFrançois Tigeot swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width); 803e3440f96SFrançois Tigeot sheight = params->src_h; 804*1e12ee3bSFrançois Tigeot iowrite32(i915_ggtt_offset(vma) + params->offset_Y, ®s->OBUF_0Y); 805e3440f96SFrançois Tigeot ostride = params->stride_Y; 806e3adcf8fSFrançois Tigeot 807e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PLANAR) { 808e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(params->format); 809e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(params->format); 810e3adcf8fSFrançois Tigeot u32 tmp_U, tmp_V; 811e3440f96SFrançois Tigeot swidth |= (params->src_w/uv_hscale) << 16; 8121487f786SFrançois Tigeot tmp_U = calc_swidthsw(dev_priv, params->offset_U, 813e3adcf8fSFrançois Tigeot params->src_w/uv_hscale); 8141487f786SFrançois Tigeot tmp_V = calc_swidthsw(dev_priv, params->offset_V, 815e3adcf8fSFrançois Tigeot params->src_w/uv_hscale); 816e3440f96SFrançois Tigeot swidthsw |= max_t(u32, tmp_U, tmp_V) << 16; 817e3440f96SFrançois Tigeot sheight |= (params->src_h/uv_vscale) << 16; 818*1e12ee3bSFrançois Tigeot iowrite32(i915_ggtt_offset(vma) + params->offset_U, 819*1e12ee3bSFrançois Tigeot ®s->OBUF_0U); 820*1e12ee3bSFrançois Tigeot iowrite32(i915_ggtt_offset(vma) + params->offset_V, 821*1e12ee3bSFrançois Tigeot ®s->OBUF_0V); 822e3440f96SFrançois Tigeot ostride |= params->stride_UV << 16; 823e3adcf8fSFrançois Tigeot } 824e3adcf8fSFrançois Tigeot 825e3440f96SFrançois Tigeot iowrite32(swidth, ®s->SWIDTH); 826e3440f96SFrançois Tigeot iowrite32(swidthsw, ®s->SWIDTHSW); 827e3440f96SFrançois Tigeot iowrite32(sheight, ®s->SHEIGHT); 828e3440f96SFrançois Tigeot iowrite32(ostride, ®s->OSTRIDE); 829e3440f96SFrançois Tigeot 830e3adcf8fSFrançois Tigeot scale_changed = update_scaling_factors(overlay, regs, params); 831e3adcf8fSFrançois Tigeot 832e3adcf8fSFrançois Tigeot update_colorkey(overlay, regs); 833e3adcf8fSFrançois Tigeot 834e3440f96SFrançois Tigeot iowrite32(overlay_cmd_reg(params), ®s->OCMD); 835e3adcf8fSFrançois Tigeot 836e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 837e3adcf8fSFrançois Tigeot 838e3adcf8fSFrançois Tigeot ret = intel_overlay_continue(overlay, scale_changed); 839e3adcf8fSFrançois Tigeot if (ret) 840e3adcf8fSFrançois Tigeot goto out_unpin; 841e3adcf8fSFrançois Tigeot 842*1e12ee3bSFrançois Tigeot i915_gem_track_fb(overlay->vma->obj, new_bo, 84324edb884SFrançois Tigeot INTEL_FRONTBUFFER_OVERLAY(pipe)); 84424edb884SFrançois Tigeot 845*1e12ee3bSFrançois Tigeot overlay->old_vma = overlay->vma; 846*1e12ee3bSFrançois Tigeot overlay->vma = vma; 847e3adcf8fSFrançois Tigeot 84871f41f3eSFrançois Tigeot intel_frontbuffer_flip(dev_priv, INTEL_FRONTBUFFER_OVERLAY(pipe)); 84924edb884SFrançois Tigeot 850e3adcf8fSFrançois Tigeot return 0; 851e3adcf8fSFrançois Tigeot 852e3adcf8fSFrançois Tigeot out_unpin: 853*1e12ee3bSFrançois Tigeot i915_gem_object_unpin_from_display_plane(vma); 854e3adcf8fSFrançois Tigeot return ret; 855e3adcf8fSFrançois Tigeot } 856e3adcf8fSFrançois Tigeot 857e3adcf8fSFrançois Tigeot int intel_overlay_switch_off(struct intel_overlay *overlay) 858e3adcf8fSFrançois Tigeot { 8591487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 860e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 861e3adcf8fSFrançois Tigeot int ret; 862e3adcf8fSFrançois Tigeot 863303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex); 864303bf270SFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex)); 865e3adcf8fSFrançois Tigeot 866e3adcf8fSFrançois Tigeot ret = intel_overlay_recover_from_interrupt(overlay); 867e3adcf8fSFrançois Tigeot if (ret != 0) 868e3adcf8fSFrançois Tigeot return ret; 869e3adcf8fSFrançois Tigeot 870e3adcf8fSFrançois Tigeot if (!overlay->active) 871e3adcf8fSFrançois Tigeot return 0; 872e3adcf8fSFrançois Tigeot 873e3adcf8fSFrançois Tigeot ret = intel_overlay_release_old_vid(overlay); 874e3adcf8fSFrançois Tigeot if (ret != 0) 875e3adcf8fSFrançois Tigeot return ret; 876e3adcf8fSFrançois Tigeot 877e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 878e3440f96SFrançois Tigeot iowrite32(0, ®s->OCMD); 879e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 880e3adcf8fSFrançois Tigeot 88171f41f3eSFrançois Tigeot return intel_overlay_off(overlay); 882e3adcf8fSFrançois Tigeot } 883e3adcf8fSFrançois Tigeot 884e3adcf8fSFrançois Tigeot static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, 885e3adcf8fSFrançois Tigeot struct intel_crtc *crtc) 886e3adcf8fSFrançois Tigeot { 887e3adcf8fSFrançois Tigeot if (!crtc->active) 888e3adcf8fSFrançois Tigeot return -EINVAL; 889e3adcf8fSFrançois Tigeot 890e3adcf8fSFrançois Tigeot /* can't use the overlay with double wide pipe */ 8912c9916cdSFrançois Tigeot if (crtc->config->double_wide) 892e3adcf8fSFrançois Tigeot return -EINVAL; 893e3adcf8fSFrançois Tigeot 894e3adcf8fSFrançois Tigeot return 0; 895e3adcf8fSFrançois Tigeot } 896e3adcf8fSFrançois Tigeot 897e3adcf8fSFrançois Tigeot static void update_pfit_vscale_ratio(struct intel_overlay *overlay) 898e3adcf8fSFrançois Tigeot { 8991487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 900e3adcf8fSFrançois Tigeot u32 pfit_control = I915_READ(PFIT_CONTROL); 901e3adcf8fSFrançois Tigeot u32 ratio; 902e3adcf8fSFrançois Tigeot 903e3adcf8fSFrançois Tigeot /* XXX: This is not the same logic as in the xorg driver, but more in 904e3adcf8fSFrançois Tigeot * line with the intel documentation for the i965 905e3adcf8fSFrançois Tigeot */ 9061487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 4) { 907e3adcf8fSFrançois Tigeot /* on i965 use the PGM reg to read out the autoscaler values */ 908e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; 909e3adcf8fSFrançois Tigeot } else { 910e3adcf8fSFrançois Tigeot if (pfit_control & VERT_AUTO_SCALE) 911e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_AUTO_RATIOS); 912e3adcf8fSFrançois Tigeot else 913e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_PGM_RATIOS); 914e3adcf8fSFrançois Tigeot ratio >>= PFIT_VERT_SCALE_SHIFT; 915e3adcf8fSFrançois Tigeot } 916e3adcf8fSFrançois Tigeot 917e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio = ratio; 918e3adcf8fSFrançois Tigeot } 919e3adcf8fSFrançois Tigeot 920e3adcf8fSFrançois Tigeot static int check_overlay_dst(struct intel_overlay *overlay, 921e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *rec) 922e3adcf8fSFrançois Tigeot { 923e3adcf8fSFrançois Tigeot struct drm_display_mode *mode = &overlay->crtc->base.mode; 924e3adcf8fSFrançois Tigeot 925e3adcf8fSFrançois Tigeot if (rec->dst_x < mode->hdisplay && 926e3adcf8fSFrançois Tigeot rec->dst_x + rec->dst_width <= mode->hdisplay && 927e3adcf8fSFrançois Tigeot rec->dst_y < mode->vdisplay && 928e3adcf8fSFrançois Tigeot rec->dst_y + rec->dst_height <= mode->vdisplay) 929e3adcf8fSFrançois Tigeot return 0; 930e3adcf8fSFrançois Tigeot else 931e3adcf8fSFrançois Tigeot return -EINVAL; 932e3adcf8fSFrançois Tigeot } 933e3adcf8fSFrançois Tigeot 934e3adcf8fSFrançois Tigeot static int check_overlay_scaling(struct put_image_params *rec) 935e3adcf8fSFrançois Tigeot { 936e3adcf8fSFrançois Tigeot u32 tmp; 937e3adcf8fSFrançois Tigeot 938e3adcf8fSFrançois Tigeot /* downscaling limit is 8.0 */ 939e3adcf8fSFrançois Tigeot tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16; 940e3adcf8fSFrançois Tigeot if (tmp > 7) 941e3adcf8fSFrançois Tigeot return -EINVAL; 942e3adcf8fSFrançois Tigeot tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16; 943e3adcf8fSFrançois Tigeot if (tmp > 7) 944e3adcf8fSFrançois Tigeot return -EINVAL; 945e3adcf8fSFrançois Tigeot 946e3adcf8fSFrançois Tigeot return 0; 947e3adcf8fSFrançois Tigeot } 948e3adcf8fSFrançois Tigeot 9491487f786SFrançois Tigeot static int check_overlay_src(struct drm_i915_private *dev_priv, 950e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *rec, 951e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo) 952e3adcf8fSFrançois Tigeot { 953e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(rec->flags); 954e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(rec->flags); 955e3adcf8fSFrançois Tigeot u32 stride_mask; 956e3adcf8fSFrançois Tigeot int depth; 957e3adcf8fSFrançois Tigeot u32 tmp; 958e3adcf8fSFrançois Tigeot 959e3adcf8fSFrançois Tigeot /* check src dimensions */ 9601487f786SFrançois Tigeot if (IS_845G(dev_priv) || IS_I830(dev_priv)) { 961e3adcf8fSFrançois Tigeot if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || 962e3adcf8fSFrançois Tigeot rec->src_width > IMAGE_MAX_WIDTH_LEGACY) 963e3adcf8fSFrançois Tigeot return -EINVAL; 964e3adcf8fSFrançois Tigeot } else { 965e3adcf8fSFrançois Tigeot if (rec->src_height > IMAGE_MAX_HEIGHT || 966e3adcf8fSFrançois Tigeot rec->src_width > IMAGE_MAX_WIDTH) 967e3adcf8fSFrançois Tigeot return -EINVAL; 968e3adcf8fSFrançois Tigeot } 969e3adcf8fSFrançois Tigeot 970e3adcf8fSFrançois Tigeot /* better safe than sorry, use 4 as the maximal subsampling ratio */ 971e3adcf8fSFrançois Tigeot if (rec->src_height < N_VERT_Y_TAPS*4 || 972e3adcf8fSFrançois Tigeot rec->src_width < N_HORIZ_Y_TAPS*4) 973e3adcf8fSFrançois Tigeot return -EINVAL; 974e3adcf8fSFrançois Tigeot 975e3adcf8fSFrançois Tigeot /* check alignment constraints */ 976e3adcf8fSFrançois Tigeot switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 977e3adcf8fSFrançois Tigeot case I915_OVERLAY_RGB: 978e3adcf8fSFrançois Tigeot /* not implemented */ 979e3adcf8fSFrançois Tigeot return -EINVAL; 980e3adcf8fSFrançois Tigeot 981e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PACKED: 982e3adcf8fSFrançois Tigeot if (uv_vscale != 1) 983e3adcf8fSFrançois Tigeot return -EINVAL; 984e3adcf8fSFrançois Tigeot 985e3adcf8fSFrançois Tigeot depth = packed_depth_bytes(rec->flags); 986e3adcf8fSFrançois Tigeot if (depth < 0) 987e3adcf8fSFrançois Tigeot return depth; 988e3adcf8fSFrançois Tigeot 989e3adcf8fSFrançois Tigeot /* ignore UV planes */ 990e3adcf8fSFrançois Tigeot rec->stride_UV = 0; 991e3adcf8fSFrançois Tigeot rec->offset_U = 0; 992e3adcf8fSFrançois Tigeot rec->offset_V = 0; 993e3adcf8fSFrançois Tigeot /* check pixel alignment */ 994e3adcf8fSFrançois Tigeot if (rec->offset_Y % depth) 995e3adcf8fSFrançois Tigeot return -EINVAL; 996e3adcf8fSFrançois Tigeot break; 997e3adcf8fSFrançois Tigeot 998e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PLANAR: 999e3adcf8fSFrançois Tigeot if (uv_vscale < 0 || uv_hscale < 0) 1000e3adcf8fSFrançois Tigeot return -EINVAL; 1001e3adcf8fSFrançois Tigeot /* no offset restrictions for planar formats */ 1002e3adcf8fSFrançois Tigeot break; 1003e3adcf8fSFrançois Tigeot 1004e3adcf8fSFrançois Tigeot default: 1005e3adcf8fSFrançois Tigeot return -EINVAL; 1006e3adcf8fSFrançois Tigeot } 1007e3adcf8fSFrançois Tigeot 1008e3adcf8fSFrançois Tigeot if (rec->src_width % uv_hscale) 1009e3adcf8fSFrançois Tigeot return -EINVAL; 1010e3adcf8fSFrançois Tigeot 1011e3adcf8fSFrançois Tigeot /* stride checking */ 10121487f786SFrançois Tigeot if (IS_I830(dev_priv) || IS_845G(dev_priv)) 1013e3adcf8fSFrançois Tigeot stride_mask = 255; 1014e3adcf8fSFrançois Tigeot else 1015e3adcf8fSFrançois Tigeot stride_mask = 63; 1016e3adcf8fSFrançois Tigeot 1017e3adcf8fSFrançois Tigeot if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) 1018e3adcf8fSFrançois Tigeot return -EINVAL; 10191487f786SFrançois Tigeot if (IS_GEN4(dev_priv) && rec->stride_Y < 512) 1020e3adcf8fSFrançois Tigeot return -EINVAL; 1021e3adcf8fSFrançois Tigeot 1022e3adcf8fSFrançois Tigeot tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? 1023e3adcf8fSFrançois Tigeot 4096 : 8192; 1024e3adcf8fSFrançois Tigeot if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) 1025e3adcf8fSFrançois Tigeot return -EINVAL; 1026e3adcf8fSFrançois Tigeot 1027e3adcf8fSFrançois Tigeot /* check buffer dimensions */ 1028e3adcf8fSFrançois Tigeot switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 1029e3adcf8fSFrançois Tigeot case I915_OVERLAY_RGB: 1030e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PACKED: 1031e3adcf8fSFrançois Tigeot /* always 4 Y values per depth pixels */ 1032e3adcf8fSFrançois Tigeot if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) 1033e3adcf8fSFrançois Tigeot return -EINVAL; 1034e3adcf8fSFrançois Tigeot 1035e3adcf8fSFrançois Tigeot tmp = rec->stride_Y*rec->src_height; 1036e3adcf8fSFrançois Tigeot if (rec->offset_Y + tmp > new_bo->base.size) 1037e3adcf8fSFrançois Tigeot return -EINVAL; 1038e3adcf8fSFrançois Tigeot break; 1039e3adcf8fSFrançois Tigeot 1040e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PLANAR: 1041e3adcf8fSFrançois Tigeot if (rec->src_width > rec->stride_Y) 1042e3adcf8fSFrançois Tigeot return -EINVAL; 1043e3adcf8fSFrançois Tigeot if (rec->src_width/uv_hscale > rec->stride_UV) 1044e3adcf8fSFrançois Tigeot return -EINVAL; 1045e3adcf8fSFrançois Tigeot 1046e3adcf8fSFrançois Tigeot tmp = rec->stride_Y * rec->src_height; 1047e3adcf8fSFrançois Tigeot if (rec->offset_Y + tmp > new_bo->base.size) 1048e3adcf8fSFrançois Tigeot return -EINVAL; 1049e3adcf8fSFrançois Tigeot 1050e3adcf8fSFrançois Tigeot tmp = rec->stride_UV * (rec->src_height / uv_vscale); 1051e3adcf8fSFrançois Tigeot if (rec->offset_U + tmp > new_bo->base.size || 1052e3adcf8fSFrançois Tigeot rec->offset_V + tmp > new_bo->base.size) 1053e3adcf8fSFrançois Tigeot return -EINVAL; 1054e3adcf8fSFrançois Tigeot break; 1055e3adcf8fSFrançois Tigeot } 1056e3adcf8fSFrançois Tigeot 1057e3adcf8fSFrançois Tigeot return 0; 1058e3adcf8fSFrançois Tigeot } 1059e3adcf8fSFrançois Tigeot 1060e3adcf8fSFrançois Tigeot /** 1061e3adcf8fSFrançois Tigeot * Return the pipe currently connected to the panel fitter, 1062e3adcf8fSFrançois Tigeot * or -1 if the panel fitter is not present or not in use 1063e3adcf8fSFrançois Tigeot */ 10641487f786SFrançois Tigeot static int intel_panel_fitter_pipe(struct drm_i915_private *dev_priv) 1065e3adcf8fSFrançois Tigeot { 1066e3adcf8fSFrançois Tigeot u32 pfit_control; 1067e3adcf8fSFrançois Tigeot 1068e3adcf8fSFrançois Tigeot /* i830 doesn't have a panel fitter */ 10691487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) <= 3 && 10701487f786SFrançois Tigeot (IS_I830(dev_priv) || !IS_MOBILE(dev_priv))) 1071e3adcf8fSFrançois Tigeot return -1; 1072e3adcf8fSFrançois Tigeot 1073e3adcf8fSFrançois Tigeot pfit_control = I915_READ(PFIT_CONTROL); 1074e3adcf8fSFrançois Tigeot 1075e3adcf8fSFrançois Tigeot /* See if the panel fitter is in use */ 1076e3adcf8fSFrançois Tigeot if ((pfit_control & PFIT_ENABLE) == 0) 1077e3adcf8fSFrançois Tigeot return -1; 1078e3adcf8fSFrançois Tigeot 1079e3adcf8fSFrançois Tigeot /* 965 can place panel fitter on either pipe */ 10801487f786SFrançois Tigeot if (IS_GEN4(dev_priv)) 1081e3adcf8fSFrançois Tigeot return (pfit_control >> 29) & 0x3; 1082e3adcf8fSFrançois Tigeot 1083e3adcf8fSFrançois Tigeot /* older chips can only use pipe 1 */ 1084e3adcf8fSFrançois Tigeot return 1; 1085e3adcf8fSFrançois Tigeot } 1086e3adcf8fSFrançois Tigeot 10871487f786SFrançois Tigeot int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, 1088e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1089e3adcf8fSFrançois Tigeot { 1090e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *put_image_rec = data; 1091bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1092e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 109324edb884SFrançois Tigeot struct drm_crtc *drmmode_crtc; 1094e3adcf8fSFrançois Tigeot struct intel_crtc *crtc; 1095e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo; 1096e3adcf8fSFrançois Tigeot struct put_image_params *params; 1097e3adcf8fSFrançois Tigeot int ret; 1098e3adcf8fSFrançois Tigeot 1099e3adcf8fSFrançois Tigeot overlay = dev_priv->overlay; 1100e3adcf8fSFrançois Tigeot if (!overlay) { 1101e3adcf8fSFrançois Tigeot DRM_DEBUG("userspace bug: no overlay\n"); 1102e3adcf8fSFrançois Tigeot return -ENODEV; 1103e3adcf8fSFrançois Tigeot } 1104e3adcf8fSFrançois Tigeot 1105e3adcf8fSFrançois Tigeot if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { 1106a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1107a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1108e3adcf8fSFrançois Tigeot 1109e3adcf8fSFrançois Tigeot ret = intel_overlay_switch_off(overlay); 1110e3adcf8fSFrançois Tigeot 1111a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1112a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1113e3adcf8fSFrançois Tigeot 1114e3adcf8fSFrançois Tigeot return ret; 1115e3adcf8fSFrançois Tigeot } 1116e3adcf8fSFrançois Tigeot 1117bf017597SFrançois Tigeot params = kmalloc(sizeof(*params), M_DRM, GFP_KERNEL); 1118e3440f96SFrançois Tigeot if (!params) 1119e3440f96SFrançois Tigeot return -ENOMEM; 1120e3adcf8fSFrançois Tigeot 112124edb884SFrançois Tigeot drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id); 112224edb884SFrançois Tigeot if (!drmmode_crtc) { 1123e3adcf8fSFrançois Tigeot ret = -ENOENT; 1124e3adcf8fSFrançois Tigeot goto out_free; 1125e3adcf8fSFrançois Tigeot } 112624edb884SFrançois Tigeot crtc = to_intel_crtc(drmmode_crtc); 1127e3adcf8fSFrançois Tigeot 112887df8fc6SFrançois Tigeot new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle); 112987df8fc6SFrançois Tigeot if (!new_bo) { 1130e3adcf8fSFrançois Tigeot ret = -ENOENT; 1131e3adcf8fSFrançois Tigeot goto out_free; 1132e3adcf8fSFrançois Tigeot } 1133e3adcf8fSFrançois Tigeot 1134a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1135a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1136e3adcf8fSFrançois Tigeot 113771f41f3eSFrançois Tigeot if (i915_gem_object_is_tiled(new_bo)) { 1138ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n"); 1139e3adcf8fSFrançois Tigeot ret = -EINVAL; 1140e3adcf8fSFrançois Tigeot goto out_unlock; 1141e3adcf8fSFrançois Tigeot } 1142e3adcf8fSFrançois Tigeot 1143e3adcf8fSFrançois Tigeot ret = intel_overlay_recover_from_interrupt(overlay); 1144e3adcf8fSFrançois Tigeot if (ret != 0) 1145e3adcf8fSFrançois Tigeot goto out_unlock; 1146e3adcf8fSFrançois Tigeot 1147e3adcf8fSFrançois Tigeot if (overlay->crtc != crtc) { 1148e3adcf8fSFrançois Tigeot struct drm_display_mode *mode = &crtc->base.mode; 1149e3adcf8fSFrançois Tigeot ret = intel_overlay_switch_off(overlay); 1150e3adcf8fSFrançois Tigeot if (ret != 0) 1151e3adcf8fSFrançois Tigeot goto out_unlock; 1152e3adcf8fSFrançois Tigeot 1153e3adcf8fSFrançois Tigeot ret = check_overlay_possible_on_crtc(overlay, crtc); 1154e3adcf8fSFrançois Tigeot if (ret != 0) 1155e3adcf8fSFrançois Tigeot goto out_unlock; 1156e3adcf8fSFrançois Tigeot 1157e3adcf8fSFrançois Tigeot overlay->crtc = crtc; 1158e3adcf8fSFrançois Tigeot crtc->overlay = overlay; 1159e3adcf8fSFrançois Tigeot 1160e3adcf8fSFrançois Tigeot /* line too wide, i.e. one-line-mode */ 1161e3adcf8fSFrançois Tigeot if (mode->hdisplay > 1024 && 11621487f786SFrançois Tigeot intel_panel_fitter_pipe(dev_priv) == crtc->pipe) { 116319c468b4SFrançois Tigeot overlay->pfit_active = true; 1164e3adcf8fSFrançois Tigeot update_pfit_vscale_ratio(overlay); 1165e3adcf8fSFrançois Tigeot } else 116619c468b4SFrançois Tigeot overlay->pfit_active = false; 1167e3adcf8fSFrançois Tigeot } 1168e3adcf8fSFrançois Tigeot 1169e3adcf8fSFrançois Tigeot ret = check_overlay_dst(overlay, put_image_rec); 1170e3adcf8fSFrançois Tigeot if (ret != 0) 1171e3adcf8fSFrançois Tigeot goto out_unlock; 1172e3adcf8fSFrançois Tigeot 1173e3adcf8fSFrançois Tigeot if (overlay->pfit_active) { 1174e3adcf8fSFrançois Tigeot params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / 1175e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio); 1176e3adcf8fSFrançois Tigeot /* shifting right rounds downwards, so add 1 */ 1177e3adcf8fSFrançois Tigeot params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / 1178e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio) + 1; 1179e3adcf8fSFrançois Tigeot } else { 1180e3adcf8fSFrançois Tigeot params->dst_y = put_image_rec->dst_y; 1181e3adcf8fSFrançois Tigeot params->dst_h = put_image_rec->dst_height; 1182e3adcf8fSFrançois Tigeot } 1183e3adcf8fSFrançois Tigeot params->dst_x = put_image_rec->dst_x; 1184e3adcf8fSFrançois Tigeot params->dst_w = put_image_rec->dst_width; 1185e3adcf8fSFrançois Tigeot 1186e3adcf8fSFrançois Tigeot params->src_w = put_image_rec->src_width; 1187e3adcf8fSFrançois Tigeot params->src_h = put_image_rec->src_height; 1188e3adcf8fSFrançois Tigeot params->src_scan_w = put_image_rec->src_scan_width; 1189e3adcf8fSFrançois Tigeot params->src_scan_h = put_image_rec->src_scan_height; 1190e3adcf8fSFrançois Tigeot if (params->src_scan_h > params->src_h || 1191e3adcf8fSFrançois Tigeot params->src_scan_w > params->src_w) { 1192e3adcf8fSFrançois Tigeot ret = -EINVAL; 1193e3adcf8fSFrançois Tigeot goto out_unlock; 1194e3adcf8fSFrançois Tigeot } 1195e3adcf8fSFrançois Tigeot 11961487f786SFrançois Tigeot ret = check_overlay_src(dev_priv, put_image_rec, new_bo); 1197e3adcf8fSFrançois Tigeot if (ret != 0) 1198e3adcf8fSFrançois Tigeot goto out_unlock; 1199e3adcf8fSFrançois Tigeot params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK; 1200e3adcf8fSFrançois Tigeot params->stride_Y = put_image_rec->stride_Y; 1201e3adcf8fSFrançois Tigeot params->stride_UV = put_image_rec->stride_UV; 1202e3adcf8fSFrançois Tigeot params->offset_Y = put_image_rec->offset_Y; 1203e3adcf8fSFrançois Tigeot params->offset_U = put_image_rec->offset_U; 1204e3adcf8fSFrançois Tigeot params->offset_V = put_image_rec->offset_V; 1205e3adcf8fSFrançois Tigeot 1206e3adcf8fSFrançois Tigeot /* Check scaling after src size to prevent a divide-by-zero. */ 1207e3adcf8fSFrançois Tigeot ret = check_overlay_scaling(params); 1208e3adcf8fSFrançois Tigeot if (ret != 0) 1209e3adcf8fSFrançois Tigeot goto out_unlock; 1210e3adcf8fSFrançois Tigeot 1211e3adcf8fSFrançois Tigeot ret = intel_overlay_do_put_image(overlay, new_bo, params); 1212e3adcf8fSFrançois Tigeot if (ret != 0) 1213e3adcf8fSFrançois Tigeot goto out_unlock; 1214e3adcf8fSFrançois Tigeot 1215a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1216a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1217e3adcf8fSFrançois Tigeot 1218158486a6SFrançois Tigeot kfree(params); 1219e3adcf8fSFrançois Tigeot 1220e3adcf8fSFrançois Tigeot return 0; 1221e3adcf8fSFrançois Tigeot 1222e3adcf8fSFrançois Tigeot out_unlock: 1223a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1224a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 122587df8fc6SFrançois Tigeot i915_gem_object_put_unlocked(new_bo); 1226e3adcf8fSFrançois Tigeot out_free: 1227158486a6SFrançois Tigeot kfree(params); 1228e3adcf8fSFrançois Tigeot 1229e3adcf8fSFrançois Tigeot return ret; 1230e3adcf8fSFrançois Tigeot } 1231e3adcf8fSFrançois Tigeot 1232e3adcf8fSFrançois Tigeot static void update_reg_attrs(struct intel_overlay *overlay, 1233e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 1234e3adcf8fSFrançois Tigeot { 1235e3440f96SFrançois Tigeot iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff), 1236e3440f96SFrançois Tigeot ®s->OCLRC0); 1237e3440f96SFrançois Tigeot iowrite32(overlay->saturation, ®s->OCLRC1); 1238e3adcf8fSFrançois Tigeot } 1239e3adcf8fSFrançois Tigeot 1240e3adcf8fSFrançois Tigeot static bool check_gamma_bounds(u32 gamma1, u32 gamma2) 1241e3adcf8fSFrançois Tigeot { 1242e3adcf8fSFrançois Tigeot int i; 1243e3adcf8fSFrançois Tigeot 1244e3adcf8fSFrançois Tigeot if (gamma1 & 0xff000000 || gamma2 & 0xff000000) 1245e3adcf8fSFrançois Tigeot return false; 1246e3adcf8fSFrançois Tigeot 1247e3adcf8fSFrançois Tigeot for (i = 0; i < 3; i++) { 1248e3adcf8fSFrançois Tigeot if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) 1249e3adcf8fSFrançois Tigeot return false; 1250e3adcf8fSFrançois Tigeot } 1251e3adcf8fSFrançois Tigeot 1252e3adcf8fSFrançois Tigeot return true; 1253e3adcf8fSFrançois Tigeot } 1254e3adcf8fSFrançois Tigeot 1255e3adcf8fSFrançois Tigeot static bool check_gamma5_errata(u32 gamma5) 1256e3adcf8fSFrançois Tigeot { 1257e3adcf8fSFrançois Tigeot int i; 1258e3adcf8fSFrançois Tigeot 1259e3adcf8fSFrançois Tigeot for (i = 0; i < 3; i++) { 1260e3adcf8fSFrançois Tigeot if (((gamma5 >> i*8) & 0xff) == 0x80) 1261e3adcf8fSFrançois Tigeot return false; 1262e3adcf8fSFrançois Tigeot } 1263e3adcf8fSFrançois Tigeot 1264e3adcf8fSFrançois Tigeot return true; 1265e3adcf8fSFrançois Tigeot } 1266e3adcf8fSFrançois Tigeot 1267e3adcf8fSFrançois Tigeot static int check_gamma(struct drm_intel_overlay_attrs *attrs) 1268e3adcf8fSFrançois Tigeot { 1269e3adcf8fSFrançois Tigeot if (!check_gamma_bounds(0, attrs->gamma0) || 1270e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || 1271e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || 1272e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || 1273e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || 1274e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || 1275e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) 1276e3adcf8fSFrançois Tigeot return -EINVAL; 1277e3adcf8fSFrançois Tigeot 1278e3adcf8fSFrançois Tigeot if (!check_gamma5_errata(attrs->gamma5)) 1279e3adcf8fSFrançois Tigeot return -EINVAL; 1280e3adcf8fSFrançois Tigeot 1281e3adcf8fSFrançois Tigeot return 0; 1282e3adcf8fSFrançois Tigeot } 1283e3adcf8fSFrançois Tigeot 12841487f786SFrançois Tigeot int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, 1285e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1286e3adcf8fSFrançois Tigeot { 1287e3adcf8fSFrançois Tigeot struct drm_intel_overlay_attrs *attrs = data; 1288bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1289e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1290e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1291e3adcf8fSFrançois Tigeot int ret; 1292e3adcf8fSFrançois Tigeot 1293e3adcf8fSFrançois Tigeot overlay = dev_priv->overlay; 1294e3adcf8fSFrançois Tigeot if (!overlay) { 1295e3adcf8fSFrançois Tigeot DRM_DEBUG("userspace bug: no overlay\n"); 1296e3adcf8fSFrançois Tigeot return -ENODEV; 1297e3adcf8fSFrançois Tigeot } 1298e3adcf8fSFrançois Tigeot 1299a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1300a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1301e3adcf8fSFrançois Tigeot 1302e3adcf8fSFrançois Tigeot ret = -EINVAL; 1303e3adcf8fSFrançois Tigeot if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { 1304e3adcf8fSFrançois Tigeot attrs->color_key = overlay->color_key; 1305e3adcf8fSFrançois Tigeot attrs->brightness = overlay->brightness; 1306e3adcf8fSFrançois Tigeot attrs->contrast = overlay->contrast; 1307e3adcf8fSFrançois Tigeot attrs->saturation = overlay->saturation; 1308e3adcf8fSFrançois Tigeot 13091487f786SFrançois Tigeot if (!IS_GEN2(dev_priv)) { 1310e3adcf8fSFrançois Tigeot attrs->gamma0 = I915_READ(OGAMC0); 1311e3adcf8fSFrançois Tigeot attrs->gamma1 = I915_READ(OGAMC1); 1312e3adcf8fSFrançois Tigeot attrs->gamma2 = I915_READ(OGAMC2); 1313e3adcf8fSFrançois Tigeot attrs->gamma3 = I915_READ(OGAMC3); 1314e3adcf8fSFrançois Tigeot attrs->gamma4 = I915_READ(OGAMC4); 1315e3adcf8fSFrançois Tigeot attrs->gamma5 = I915_READ(OGAMC5); 1316e3adcf8fSFrançois Tigeot } 1317e3adcf8fSFrançois Tigeot } else { 1318e3adcf8fSFrançois Tigeot if (attrs->brightness < -128 || attrs->brightness > 127) 1319e3adcf8fSFrançois Tigeot goto out_unlock; 1320e3adcf8fSFrançois Tigeot if (attrs->contrast > 255) 1321e3adcf8fSFrançois Tigeot goto out_unlock; 1322e3adcf8fSFrançois Tigeot if (attrs->saturation > 1023) 1323e3adcf8fSFrançois Tigeot goto out_unlock; 1324e3adcf8fSFrançois Tigeot 1325e3adcf8fSFrançois Tigeot overlay->color_key = attrs->color_key; 1326e3adcf8fSFrançois Tigeot overlay->brightness = attrs->brightness; 1327e3adcf8fSFrançois Tigeot overlay->contrast = attrs->contrast; 1328e3adcf8fSFrançois Tigeot overlay->saturation = attrs->saturation; 1329e3adcf8fSFrançois Tigeot 1330e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 1331e3adcf8fSFrançois Tigeot if (!regs) { 1332e3adcf8fSFrançois Tigeot ret = -ENOMEM; 1333e3adcf8fSFrançois Tigeot goto out_unlock; 1334e3adcf8fSFrançois Tigeot } 1335e3adcf8fSFrançois Tigeot 1336e3adcf8fSFrançois Tigeot update_reg_attrs(overlay, regs); 1337e3adcf8fSFrançois Tigeot 1338e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 1339e3adcf8fSFrançois Tigeot 1340e3adcf8fSFrançois Tigeot if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { 13411487f786SFrançois Tigeot if (IS_GEN2(dev_priv)) 1342e3adcf8fSFrançois Tigeot goto out_unlock; 1343e3adcf8fSFrançois Tigeot 1344e3adcf8fSFrançois Tigeot if (overlay->active) { 1345e3adcf8fSFrançois Tigeot ret = -EBUSY; 1346e3adcf8fSFrançois Tigeot goto out_unlock; 1347e3adcf8fSFrançois Tigeot } 1348e3adcf8fSFrançois Tigeot 1349e3adcf8fSFrançois Tigeot ret = check_gamma(attrs); 1350e3adcf8fSFrançois Tigeot if (ret) 1351e3adcf8fSFrançois Tigeot goto out_unlock; 1352e3adcf8fSFrançois Tigeot 1353e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC0, attrs->gamma0); 1354e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC1, attrs->gamma1); 1355e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC2, attrs->gamma2); 1356e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC3, attrs->gamma3); 1357e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC4, attrs->gamma4); 1358e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC5, attrs->gamma5); 1359e3adcf8fSFrançois Tigeot } 1360e3adcf8fSFrançois Tigeot } 136119c468b4SFrançois Tigeot overlay->color_key_enabled = (attrs->flags & I915_OVERLAY_DISABLE_DEST_COLORKEY) == 0; 1362e3adcf8fSFrançois Tigeot 1363e3adcf8fSFrançois Tigeot ret = 0; 1364e3adcf8fSFrançois Tigeot out_unlock: 1365a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1366a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1367e3adcf8fSFrançois Tigeot 1368e3adcf8fSFrançois Tigeot return ret; 1369e3adcf8fSFrançois Tigeot } 1370e3adcf8fSFrançois Tigeot 13711487f786SFrançois Tigeot void intel_setup_overlay(struct drm_i915_private *dev_priv) 1372e3adcf8fSFrançois Tigeot { 1373e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1374e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *reg_bo; 1375e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1376*1e12ee3bSFrançois Tigeot struct i915_vma *vma = NULL; 1377e3adcf8fSFrançois Tigeot int ret; 1378e3adcf8fSFrançois Tigeot 13791487f786SFrançois Tigeot if (!HAS_OVERLAY(dev_priv)) 1380e3adcf8fSFrançois Tigeot return; 1381e3adcf8fSFrançois Tigeot 13829edbd4a0SFrançois Tigeot overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); 1383e3440f96SFrançois Tigeot if (!overlay) 1384e3440f96SFrançois Tigeot return; 1385e3440f96SFrançois Tigeot 1386303bf270SFrançois Tigeot mutex_lock(&dev_priv->drm.struct_mutex); 1387e3440f96SFrançois Tigeot if (WARN_ON(dev_priv->overlay)) 1388e3adcf8fSFrançois Tigeot goto out_free; 1389e3440f96SFrançois Tigeot 13901487f786SFrançois Tigeot overlay->i915 = dev_priv; 1391e3adcf8fSFrançois Tigeot 13929edbd4a0SFrançois Tigeot reg_bo = NULL; 13931487f786SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(dev_priv)) 1394303bf270SFrançois Tigeot reg_bo = i915_gem_object_create_stolen(&dev_priv->drm, 1395303bf270SFrançois Tigeot PAGE_SIZE); 13969edbd4a0SFrançois Tigeot if (reg_bo == NULL) 1397303bf270SFrançois Tigeot reg_bo = i915_gem_object_create(&dev_priv->drm, PAGE_SIZE); 13981487f786SFrançois Tigeot if (IS_ERR(reg_bo)) 1399e3adcf8fSFrançois Tigeot goto out_free; 1400e3adcf8fSFrançois Tigeot overlay->reg_bo = reg_bo; 1401e3adcf8fSFrançois Tigeot 14021487f786SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) { 1403ba55f2f5SFrançois Tigeot ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE); 1404e3adcf8fSFrançois Tigeot if (ret) { 1405e3adcf8fSFrançois Tigeot DRM_ERROR("failed to attach phys overlay regs\n"); 1406e3adcf8fSFrançois Tigeot goto out_free_bo; 1407e3adcf8fSFrançois Tigeot } 1408ba55f2f5SFrançois Tigeot overlay->flip_addr = reg_bo->phys_handle->busaddr; 1409e3adcf8fSFrançois Tigeot } else { 1410*1e12ee3bSFrançois Tigeot vma = i915_gem_object_ggtt_pin(reg_bo, NULL, 141171f41f3eSFrançois Tigeot 0, PAGE_SIZE, PIN_MAPPABLE); 1412*1e12ee3bSFrançois Tigeot if (IS_ERR(vma)) { 1413e3adcf8fSFrançois Tigeot DRM_ERROR("failed to pin overlay register bo\n"); 1414*1e12ee3bSFrançois Tigeot ret = PTR_ERR(vma); 1415e3adcf8fSFrançois Tigeot goto out_free_bo; 1416e3adcf8fSFrançois Tigeot } 1417*1e12ee3bSFrançois Tigeot overlay->flip_addr = i915_ggtt_offset(vma); 1418e3adcf8fSFrançois Tigeot 1419e3adcf8fSFrançois Tigeot ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); 1420e3adcf8fSFrançois Tigeot if (ret) { 1421e3adcf8fSFrançois Tigeot DRM_ERROR("failed to move overlay register bo into the GTT\n"); 1422e3adcf8fSFrançois Tigeot goto out_unpin_bo; 1423e3adcf8fSFrançois Tigeot } 1424e3adcf8fSFrançois Tigeot } 1425e3adcf8fSFrançois Tigeot 1426e3adcf8fSFrançois Tigeot /* init all values */ 1427e3adcf8fSFrançois Tigeot overlay->color_key = 0x0101fe; 142819c468b4SFrançois Tigeot overlay->color_key_enabled = true; 1429e3adcf8fSFrançois Tigeot overlay->brightness = -19; 1430e3adcf8fSFrançois Tigeot overlay->contrast = 75; 1431e3adcf8fSFrançois Tigeot overlay->saturation = 146; 1432e3adcf8fSFrançois Tigeot 1433e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 1434e3adcf8fSFrançois Tigeot if (!regs) 1435e3adcf8fSFrançois Tigeot goto out_unpin_bo; 1436e3adcf8fSFrançois Tigeot 1437e3440f96SFrançois Tigeot memset_io(regs, 0, sizeof(struct overlay_registers)); 1438e3adcf8fSFrançois Tigeot update_polyphase_filter(regs); 1439e3adcf8fSFrançois Tigeot update_reg_attrs(overlay, regs); 1440e3adcf8fSFrançois Tigeot 1441e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 1442e3adcf8fSFrançois Tigeot 1443e3adcf8fSFrançois Tigeot dev_priv->overlay = overlay; 1444303bf270SFrançois Tigeot mutex_unlock(&dev_priv->drm.struct_mutex); 1445e3440f96SFrançois Tigeot DRM_INFO("initialized overlay support\n"); 1446e3adcf8fSFrançois Tigeot return; 1447e3adcf8fSFrançois Tigeot 1448e3adcf8fSFrançois Tigeot out_unpin_bo: 1449*1e12ee3bSFrançois Tigeot if (vma) 1450*1e12ee3bSFrançois Tigeot i915_vma_unpin(vma); 1451e3adcf8fSFrançois Tigeot out_free_bo: 145287df8fc6SFrançois Tigeot i915_gem_object_put(reg_bo); 1453e3adcf8fSFrançois Tigeot out_free: 1454303bf270SFrançois Tigeot mutex_unlock(&dev_priv->drm.struct_mutex); 1455158486a6SFrançois Tigeot kfree(overlay); 1456e3adcf8fSFrançois Tigeot return; 1457e3adcf8fSFrançois Tigeot } 1458e3adcf8fSFrançois Tigeot 14591487f786SFrançois Tigeot void intel_cleanup_overlay(struct drm_i915_private *dev_priv) 1460e3adcf8fSFrançois Tigeot { 1461e3adcf8fSFrançois Tigeot if (!dev_priv->overlay) 1462e3adcf8fSFrançois Tigeot return; 1463e3adcf8fSFrançois Tigeot 1464e3adcf8fSFrançois Tigeot /* The bo's should be free'd by the generic code already. 1465e3adcf8fSFrançois Tigeot * Furthermore modesetting teardown happens beforehand so the 1466e3adcf8fSFrançois Tigeot * hardware should be off already */ 146719c468b4SFrançois Tigeot WARN_ON(dev_priv->overlay->active); 1468e3adcf8fSFrançois Tigeot 146987df8fc6SFrançois Tigeot i915_gem_object_put_unlocked(dev_priv->overlay->reg_bo); 1470158486a6SFrançois Tigeot kfree(dev_priv->overlay); 1471e3adcf8fSFrançois Tigeot } 1472e3adcf8fSFrançois Tigeot 1473*1e12ee3bSFrançois Tigeot #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) 1474*1e12ee3bSFrançois Tigeot 1475e3adcf8fSFrançois Tigeot struct intel_overlay_error_state { 1476e3adcf8fSFrançois Tigeot struct overlay_registers regs; 1477e3adcf8fSFrançois Tigeot unsigned long base; 1478e3adcf8fSFrançois Tigeot u32 dovsta; 1479e3adcf8fSFrançois Tigeot u32 isr; 1480e3adcf8fSFrançois Tigeot }; 1481e3adcf8fSFrançois Tigeot 1482e3440f96SFrançois Tigeot static struct overlay_registers __iomem * 1483e3440f96SFrançois Tigeot intel_overlay_map_regs_atomic(struct intel_overlay *overlay) 1484e3440f96SFrançois Tigeot { 14851487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 1486e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1487e3440f96SFrançois Tigeot 14881487f786SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) 1489e3440f96SFrançois Tigeot /* Cast to make sparse happy, but it's wc memory anyway, so 1490e3440f96SFrançois Tigeot * equivalent to the wc io mapping on X86. */ 1491e3440f96SFrançois Tigeot regs = (struct overlay_registers __iomem *) 14922c9916cdSFrançois Tigeot overlay->reg_bo->phys_handle->vaddr; 1493e3440f96SFrançois Tigeot else 1494*1e12ee3bSFrançois Tigeot regs = io_mapping_map_atomic_wc(&dev_priv->ggtt.mappable, 14951487f786SFrançois Tigeot overlay->flip_addr); 1496e3440f96SFrançois Tigeot 1497e3440f96SFrançois Tigeot return regs; 1498e3440f96SFrançois Tigeot } 1499e3440f96SFrançois Tigeot 1500e3440f96SFrançois Tigeot static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, 1501e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 1502e3440f96SFrançois Tigeot { 15031487f786SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915)) 1504e3440f96SFrançois Tigeot io_mapping_unmap_atomic(regs); 1505e3440f96SFrançois Tigeot } 1506e3440f96SFrançois Tigeot 1507e3adcf8fSFrançois Tigeot struct intel_overlay_error_state * 15081487f786SFrançois Tigeot intel_overlay_capture_error_state(struct drm_i915_private *dev_priv) 1509e3adcf8fSFrançois Tigeot { 1510e3adcf8fSFrançois Tigeot struct intel_overlay *overlay = dev_priv->overlay; 1511e3adcf8fSFrançois Tigeot struct intel_overlay_error_state *error; 1512e3adcf8fSFrançois Tigeot struct overlay_registers __iomem *regs; 1513e3adcf8fSFrançois Tigeot 1514e3adcf8fSFrançois Tigeot if (!overlay || !overlay->active) 1515e3adcf8fSFrançois Tigeot return NULL; 1516e3adcf8fSFrançois Tigeot 1517bf017597SFrançois Tigeot error = kmalloc(sizeof(*error), M_DRM, GFP_ATOMIC); 1518e3adcf8fSFrançois Tigeot if (error == NULL) 1519e3adcf8fSFrançois Tigeot return NULL; 1520e3adcf8fSFrançois Tigeot 1521e3adcf8fSFrançois Tigeot error->dovsta = I915_READ(DOVSTA); 1522e3adcf8fSFrançois Tigeot error->isr = I915_READ(ISR); 15231487f786SFrançois Tigeot error->base = overlay->flip_addr; 1524e3adcf8fSFrançois Tigeot 1525e3440f96SFrançois Tigeot regs = intel_overlay_map_regs_atomic(overlay); 1526e3adcf8fSFrançois Tigeot if (!regs) 1527e3adcf8fSFrançois Tigeot goto err; 1528e3adcf8fSFrançois Tigeot 1529e3440f96SFrançois Tigeot memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); 1530e3440f96SFrançois Tigeot intel_overlay_unmap_regs_atomic(overlay, regs); 1531e3adcf8fSFrançois Tigeot 1532e3440f96SFrançois Tigeot return error; 1533e3adcf8fSFrançois Tigeot 1534e3adcf8fSFrançois Tigeot err: 1535158486a6SFrançois Tigeot kfree(error); 1536e3440f96SFrançois Tigeot return NULL; 1537e3adcf8fSFrançois Tigeot } 1538e3adcf8fSFrançois Tigeot 1539e3adcf8fSFrançois Tigeot void 15405d0b1887SFrançois Tigeot intel_overlay_print_error_state(struct drm_i915_error_state_buf *m, 15415d0b1887SFrançois Tigeot struct intel_overlay_error_state *error) 1542e3adcf8fSFrançois Tigeot { 15435d0b1887SFrançois Tigeot i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", 1544e3adcf8fSFrançois Tigeot error->dovsta, error->isr); 15455d0b1887SFrançois Tigeot i915_error_printf(m, " Register file at 0x%08lx:\n", 1546e3adcf8fSFrançois Tigeot error->base); 1547e3adcf8fSFrançois Tigeot 15485d0b1887SFrançois Tigeot #define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x) 1549e3adcf8fSFrançois Tigeot P(OBUF_0Y); 1550e3adcf8fSFrançois Tigeot P(OBUF_1Y); 1551e3adcf8fSFrançois Tigeot P(OBUF_0U); 1552e3adcf8fSFrançois Tigeot P(OBUF_0V); 1553e3adcf8fSFrançois Tigeot P(OBUF_1U); 1554e3adcf8fSFrançois Tigeot P(OBUF_1V); 1555e3adcf8fSFrançois Tigeot P(OSTRIDE); 1556e3adcf8fSFrançois Tigeot P(YRGB_VPH); 1557e3adcf8fSFrançois Tigeot P(UV_VPH); 1558e3adcf8fSFrançois Tigeot P(HORZ_PH); 1559e3adcf8fSFrançois Tigeot P(INIT_PHS); 1560e3adcf8fSFrançois Tigeot P(DWINPOS); 1561e3adcf8fSFrançois Tigeot P(DWINSZ); 1562e3adcf8fSFrançois Tigeot P(SWIDTH); 1563e3adcf8fSFrançois Tigeot P(SWIDTHSW); 1564e3adcf8fSFrançois Tigeot P(SHEIGHT); 1565e3adcf8fSFrançois Tigeot P(YRGBSCALE); 1566e3adcf8fSFrançois Tigeot P(UVSCALE); 1567e3adcf8fSFrançois Tigeot P(OCLRC0); 1568e3adcf8fSFrançois Tigeot P(OCLRC1); 1569e3adcf8fSFrançois Tigeot P(DCLRKV); 1570e3adcf8fSFrançois Tigeot P(DCLRKM); 1571e3adcf8fSFrançois Tigeot P(SCLRKVH); 1572e3adcf8fSFrançois Tigeot P(SCLRKVL); 1573e3adcf8fSFrançois Tigeot P(SCLRKEN); 1574e3adcf8fSFrançois Tigeot P(OCONFIG); 1575e3adcf8fSFrançois Tigeot P(OCMD); 1576e3adcf8fSFrançois Tigeot P(OSTART_0Y); 1577e3adcf8fSFrançois Tigeot P(OSTART_1Y); 1578e3adcf8fSFrançois Tigeot P(OSTART_0U); 1579e3adcf8fSFrançois Tigeot P(OSTART_0V); 1580e3adcf8fSFrançois Tigeot P(OSTART_1U); 1581e3adcf8fSFrançois Tigeot P(OSTART_1V); 1582e3adcf8fSFrançois Tigeot P(OTILEOFF_0Y); 1583e3adcf8fSFrançois Tigeot P(OTILEOFF_1Y); 1584e3adcf8fSFrançois Tigeot P(OTILEOFF_0U); 1585e3adcf8fSFrançois Tigeot P(OTILEOFF_0V); 1586e3adcf8fSFrançois Tigeot P(OTILEOFF_1U); 1587e3adcf8fSFrançois Tigeot P(OTILEOFF_1V); 1588e3adcf8fSFrançois Tigeot P(FASTHSCALE); 1589e3adcf8fSFrançois Tigeot P(UVSCALEV); 1590e3adcf8fSFrançois Tigeot #undef P 1591e3adcf8fSFrançois Tigeot } 1592*1e12ee3bSFrançois Tigeot 1593*1e12ee3bSFrançois Tigeot #endif 1594