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 { 1711487f786SFrançois Tigeot struct drm_i915_private *i915; 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; 17519c468b4SFrançois Tigeot bool active; 17619c468b4SFrançois Tigeot bool pfit_active; 177e3adcf8fSFrançois Tigeot u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ 17819c468b4SFrançois Tigeot u32 color_key:24; 17919c468b4SFrançois Tigeot u32 color_key_enabled:1; 180e3adcf8fSFrançois Tigeot u32 brightness, contrast, saturation; 181e3adcf8fSFrançois Tigeot u32 old_xscale, old_yscale; 182e3adcf8fSFrançois Tigeot /* register access */ 183e3adcf8fSFrançois Tigeot u32 flip_addr; 184e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *reg_bo; 185e3adcf8fSFrançois Tigeot /* flip handling */ 1862c9916cdSFrançois Tigeot struct drm_i915_gem_request *last_flip_req; 187e3adcf8fSFrançois Tigeot void (*flip_tail)(struct intel_overlay *); 188e3adcf8fSFrançois Tigeot }; 189e3adcf8fSFrançois Tigeot 190e3440f96SFrançois Tigeot static struct overlay_registers __iomem * 191e3adcf8fSFrançois Tigeot intel_overlay_map_regs(struct intel_overlay *overlay) 192e3adcf8fSFrançois Tigeot { 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 1991487f786SFranç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)) 210*bf017597SFrançois Tigeot io_mapping_unmap(regs); 211e3adcf8fSFrançois Tigeot } 212e3adcf8fSFrançois Tigeot 213e3adcf8fSFrançois Tigeot static int intel_overlay_do_wait_request(struct intel_overlay *overlay, 214a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req, 215e3adcf8fSFrançois Tigeot void (*tail)(struct intel_overlay *)) 216e3adcf8fSFrançois Tigeot { 217e3adcf8fSFrançois Tigeot int ret; 218e3adcf8fSFrançois Tigeot 21919c468b4SFrançois Tigeot WARN_ON(overlay->last_flip_req); 220a05eeebfSFrançois Tigeot i915_gem_request_assign(&overlay->last_flip_req, req); 221a05eeebfSFrançois Tigeot i915_add_request(req); 222f192107fSFrançois Tigeot 223e3adcf8fSFrançois Tigeot overlay->flip_tail = tail; 2242c9916cdSFrançois Tigeot ret = i915_wait_request(overlay->last_flip_req); 225e3adcf8fSFrançois Tigeot if (ret) 226e3adcf8fSFrançois Tigeot return ret; 227e3adcf8fSFrançois Tigeot 2282c9916cdSFrançois Tigeot i915_gem_request_assign(&overlay->last_flip_req, NULL); 229e3adcf8fSFrançois Tigeot return 0; 230e3adcf8fSFrançois Tigeot } 231e3adcf8fSFrançois Tigeot 232e3adcf8fSFrançois Tigeot /* overlay needs to be disable in OCMD reg */ 233e3adcf8fSFrançois Tigeot static int intel_overlay_on(struct intel_overlay *overlay) 234e3adcf8fSFrançois Tigeot { 2351487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 2368621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[RCS]; 237a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 238e3adcf8fSFrançois Tigeot int ret; 239e3adcf8fSFrançois Tigeot 24019c468b4SFrançois Tigeot WARN_ON(overlay->active); 2411487f786SFrançois Tigeot WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE)); 242e3adcf8fSFrançois Tigeot 2438621f407SFrançois Tigeot req = i915_gem_request_alloc(engine, NULL); 244c0e85e96SFrançois Tigeot if (IS_ERR(req)) 245c0e85e96SFrançois Tigeot return PTR_ERR(req); 246f192107fSFrançois Tigeot 247a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 4); 248a05eeebfSFrançois Tigeot if (ret) { 2498621f407SFrançois Tigeot i915_add_request_no_flush(req); 250a05eeebfSFrançois Tigeot return ret; 251a05eeebfSFrançois Tigeot } 252a05eeebfSFrançois Tigeot 25319c468b4SFrançois Tigeot overlay->active = true; 25419c468b4SFrançois Tigeot 2558621f407SFrançois Tigeot intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_ON); 2568621f407SFrançois Tigeot intel_ring_emit(engine, overlay->flip_addr | OFC_UPDATE); 2578621f407SFrançois Tigeot intel_ring_emit(engine, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 2588621f407SFrançois Tigeot intel_ring_emit(engine, MI_NOOP); 2598621f407SFrançois Tigeot intel_ring_advance(engine); 260f192107fSFrançois Tigeot 261a05eeebfSFrançois Tigeot return intel_overlay_do_wait_request(overlay, req, NULL); 262e3adcf8fSFrançois Tigeot } 263e3adcf8fSFrançois Tigeot 264e3adcf8fSFrançois Tigeot /* overlay needs to be enabled in OCMD reg */ 265e3adcf8fSFrançois Tigeot static int intel_overlay_continue(struct intel_overlay *overlay, 266e3adcf8fSFrançois Tigeot bool load_polyphase_filter) 267e3adcf8fSFrançois Tigeot { 2681487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 2698621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[RCS]; 270a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 271e3adcf8fSFrançois Tigeot u32 flip_addr = overlay->flip_addr; 272e3adcf8fSFrançois Tigeot u32 tmp; 273e3adcf8fSFrançois Tigeot int ret; 274e3adcf8fSFrançois Tigeot 27519c468b4SFrançois Tigeot WARN_ON(!overlay->active); 276e3adcf8fSFrançois Tigeot 277e3adcf8fSFrançois Tigeot if (load_polyphase_filter) 278e3adcf8fSFrançois Tigeot flip_addr |= OFC_UPDATE; 279e3adcf8fSFrançois Tigeot 280e3adcf8fSFrançois Tigeot /* check for underruns */ 281e3adcf8fSFrançois Tigeot tmp = I915_READ(DOVSTA); 282e3adcf8fSFrançois Tigeot if (tmp & (1 << 17)) 283e3adcf8fSFrançois Tigeot DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); 284e3adcf8fSFrançois Tigeot 2858621f407SFrançois Tigeot req = i915_gem_request_alloc(engine, NULL); 286c0e85e96SFrançois Tigeot if (IS_ERR(req)) 287c0e85e96SFrançois Tigeot return PTR_ERR(req); 288e3adcf8fSFrançois Tigeot 289a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 2); 290a05eeebfSFrançois Tigeot if (ret) { 2918621f407SFrançois Tigeot i915_add_request_no_flush(req); 292a05eeebfSFrançois Tigeot return ret; 293a05eeebfSFrançois Tigeot } 294a05eeebfSFrançois Tigeot 2958621f407SFrançois Tigeot intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 2968621f407SFrançois Tigeot intel_ring_emit(engine, flip_addr); 2978621f407SFrançois Tigeot intel_ring_advance(engine); 298e3adcf8fSFrançois Tigeot 2992c9916cdSFrançois Tigeot WARN_ON(overlay->last_flip_req); 300a05eeebfSFrançois Tigeot i915_gem_request_assign(&overlay->last_flip_req, req); 301a05eeebfSFrançois Tigeot i915_add_request(req); 302a05eeebfSFrançois Tigeot 303a05eeebfSFrançois Tigeot return 0; 304e3adcf8fSFrançois Tigeot } 305e3adcf8fSFrançois Tigeot 306e3adcf8fSFrançois Tigeot static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) 307e3adcf8fSFrançois Tigeot { 308e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj = overlay->old_vid_bo; 309e3adcf8fSFrançois Tigeot 310ba55f2f5SFrançois Tigeot i915_gem_object_ggtt_unpin(obj); 311e3adcf8fSFrançois Tigeot drm_gem_object_unreference(&obj->base); 312e3adcf8fSFrançois Tigeot 313e3adcf8fSFrançois Tigeot overlay->old_vid_bo = NULL; 314e3adcf8fSFrançois Tigeot } 315e3adcf8fSFrançois Tigeot 316e3adcf8fSFrançois Tigeot static void intel_overlay_off_tail(struct intel_overlay *overlay) 317e3adcf8fSFrançois Tigeot { 318e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *obj = overlay->vid_bo; 319e3adcf8fSFrançois Tigeot 320e3adcf8fSFrançois Tigeot /* never have the overlay hw on without showing a frame */ 32119c468b4SFrançois Tigeot if (WARN_ON(!obj)) 32219c468b4SFrançois Tigeot return; 323e3adcf8fSFrançois Tigeot 324ba55f2f5SFrançois Tigeot i915_gem_object_ggtt_unpin(obj); 325e3adcf8fSFrançois Tigeot drm_gem_object_unreference(&obj->base); 326e3adcf8fSFrançois Tigeot overlay->vid_bo = NULL; 327e3adcf8fSFrançois Tigeot 328e3adcf8fSFrançois Tigeot overlay->crtc->overlay = NULL; 329e3adcf8fSFrançois Tigeot overlay->crtc = NULL; 33019c468b4SFrançois Tigeot overlay->active = false; 331e3adcf8fSFrançois Tigeot } 332e3adcf8fSFrançois Tigeot 333e3adcf8fSFrançois Tigeot /* overlay needs to be disabled in OCMD reg */ 334e3adcf8fSFrançois Tigeot static int intel_overlay_off(struct intel_overlay *overlay) 335e3adcf8fSFrançois Tigeot { 3361487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 3378621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[RCS]; 338a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 339e3adcf8fSFrançois Tigeot u32 flip_addr = overlay->flip_addr; 340e3adcf8fSFrançois Tigeot int ret; 341e3adcf8fSFrançois Tigeot 34219c468b4SFrançois Tigeot WARN_ON(!overlay->active); 343e3adcf8fSFrançois Tigeot 344e3adcf8fSFrançois Tigeot /* According to intel docs the overlay hw may hang (when switching 345e3adcf8fSFrançois Tigeot * off) without loading the filter coeffs. It is however unclear whether 346e3adcf8fSFrançois Tigeot * this applies to the disabling of the overlay or to the switching off 347e3adcf8fSFrançois Tigeot * of the hw. Do it in both cases */ 348e3adcf8fSFrançois Tigeot flip_addr |= OFC_UPDATE; 349e3adcf8fSFrançois Tigeot 3508621f407SFrançois Tigeot req = i915_gem_request_alloc(engine, NULL); 351c0e85e96SFrançois Tigeot if (IS_ERR(req)) 352c0e85e96SFrançois Tigeot return PTR_ERR(req); 353e3adcf8fSFrançois Tigeot 354a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 6); 355a05eeebfSFrançois Tigeot if (ret) { 3568621f407SFrançois Tigeot i915_add_request_no_flush(req); 357a05eeebfSFrançois Tigeot return ret; 358a05eeebfSFrançois Tigeot } 359a05eeebfSFrançois Tigeot 360f192107fSFrançois Tigeot /* wait for overlay to go idle */ 3618621f407SFrançois Tigeot intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 3628621f407SFrançois Tigeot intel_ring_emit(engine, flip_addr); 3638621f407SFrançois Tigeot intel_ring_emit(engine, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 364f192107fSFrançois Tigeot /* turn overlay off */ 3651487f786SFrançois Tigeot if (IS_I830(dev_priv)) { 36619df918dSFrançois Tigeot /* Workaround: Don't disable the overlay fully, since otherwise 36719df918dSFrançois Tigeot * it dies on the next OVERLAY_ON cmd. */ 3688621f407SFrançois Tigeot intel_ring_emit(engine, MI_NOOP); 3698621f407SFrançois Tigeot intel_ring_emit(engine, MI_NOOP); 3708621f407SFrançois Tigeot intel_ring_emit(engine, MI_NOOP); 37119df918dSFrançois Tigeot } else { 3728621f407SFrançois Tigeot intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_OFF); 3738621f407SFrançois Tigeot intel_ring_emit(engine, flip_addr); 3748621f407SFrançois Tigeot intel_ring_emit(engine, 3758621f407SFrançois Tigeot MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 37619df918dSFrançois Tigeot } 3778621f407SFrançois Tigeot intel_ring_advance(engine); 378f192107fSFrançois Tigeot 379a05eeebfSFrançois Tigeot return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail); 380e3adcf8fSFrançois Tigeot } 381e3adcf8fSFrançois Tigeot 382e3adcf8fSFrançois Tigeot /* recover from an interruption due to a signal 383e3adcf8fSFrançois Tigeot * We have to be careful not to repeat work forever an make forward progess. */ 384e3adcf8fSFrançois Tigeot static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) 385e3adcf8fSFrançois Tigeot { 386e3adcf8fSFrançois Tigeot int ret; 387e3adcf8fSFrançois Tigeot 3882c9916cdSFrançois Tigeot if (overlay->last_flip_req == NULL) 389e3adcf8fSFrançois Tigeot return 0; 390e3adcf8fSFrançois Tigeot 3912c9916cdSFrançois Tigeot ret = i915_wait_request(overlay->last_flip_req); 392e3adcf8fSFrançois Tigeot if (ret) 393e3adcf8fSFrançois Tigeot return ret; 394e3adcf8fSFrançois Tigeot 395e3adcf8fSFrançois Tigeot if (overlay->flip_tail) 396e3adcf8fSFrançois Tigeot overlay->flip_tail(overlay); 397e3adcf8fSFrançois Tigeot 3982c9916cdSFrançois Tigeot i915_gem_request_assign(&overlay->last_flip_req, NULL); 399e3adcf8fSFrançois Tigeot return 0; 400e3adcf8fSFrançois Tigeot } 401e3adcf8fSFrançois Tigeot 402e3adcf8fSFrançois Tigeot /* Wait for pending overlay flip and release old frame. 403e3adcf8fSFrançois Tigeot * Needs to be called before the overlay register are changed 404e3adcf8fSFrançois Tigeot * via intel_overlay_(un)map_regs 405e3adcf8fSFrançois Tigeot */ 406e3adcf8fSFrançois Tigeot static int intel_overlay_release_old_vid(struct intel_overlay *overlay) 407e3adcf8fSFrançois Tigeot { 4081487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 4098621f407SFrançois Tigeot struct intel_engine_cs *engine = &dev_priv->engine[RCS]; 410e3adcf8fSFrançois Tigeot int ret; 411e3adcf8fSFrançois Tigeot 412303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex); 4132c9916cdSFrançois Tigeot 414e3adcf8fSFrançois Tigeot /* Only wait if there is actually an old frame to release to 415e3adcf8fSFrançois Tigeot * guarantee forward progress. 416e3adcf8fSFrançois Tigeot */ 417e3adcf8fSFrançois Tigeot if (!overlay->old_vid_bo) 418e3adcf8fSFrançois Tigeot return 0; 419e3adcf8fSFrançois Tigeot 420e3adcf8fSFrançois Tigeot if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { 421e3adcf8fSFrançois Tigeot /* synchronous slowpath */ 422a05eeebfSFrançois Tigeot struct drm_i915_gem_request *req; 423a05eeebfSFrançois Tigeot 4248621f407SFrançois Tigeot req = i915_gem_request_alloc(engine, NULL); 425c0e85e96SFrançois Tigeot if (IS_ERR(req)) 426c0e85e96SFrançois Tigeot return PTR_ERR(req); 427e3adcf8fSFrançois Tigeot 428a05eeebfSFrançois Tigeot ret = intel_ring_begin(req, 2); 429a05eeebfSFrançois Tigeot if (ret) { 4308621f407SFrançois Tigeot i915_add_request_no_flush(req); 431a05eeebfSFrançois Tigeot return ret; 432a05eeebfSFrançois Tigeot } 433a05eeebfSFrançois Tigeot 4348621f407SFrançois Tigeot intel_ring_emit(engine, 4358621f407SFrançois Tigeot MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 4368621f407SFrançois Tigeot intel_ring_emit(engine, MI_NOOP); 4378621f407SFrançois Tigeot intel_ring_advance(engine); 438e3adcf8fSFrançois Tigeot 439a05eeebfSFrançois Tigeot ret = intel_overlay_do_wait_request(overlay, req, 440e3adcf8fSFrançois Tigeot intel_overlay_release_old_vid_tail); 441e3adcf8fSFrançois Tigeot if (ret) 442e3adcf8fSFrançois Tigeot return ret; 443e3adcf8fSFrançois Tigeot } 444e3adcf8fSFrançois Tigeot 445e3adcf8fSFrançois Tigeot intel_overlay_release_old_vid_tail(overlay); 44624edb884SFrançois Tigeot 44724edb884SFrançois Tigeot 44824edb884SFrançois Tigeot i915_gem_track_fb(overlay->old_vid_bo, NULL, 44924edb884SFrançois Tigeot INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe)); 450e3adcf8fSFrançois Tigeot return 0; 451e3adcf8fSFrançois Tigeot } 452e3adcf8fSFrançois Tigeot 4532c9916cdSFrançois Tigeot void intel_overlay_reset(struct drm_i915_private *dev_priv) 4542c9916cdSFrançois Tigeot { 4552c9916cdSFrançois Tigeot struct intel_overlay *overlay = dev_priv->overlay; 4562c9916cdSFrançois Tigeot 4572c9916cdSFrançois Tigeot if (!overlay) 4582c9916cdSFrançois Tigeot return; 4592c9916cdSFrançois Tigeot 4602c9916cdSFrançois Tigeot intel_overlay_release_old_vid(overlay); 4612c9916cdSFrançois Tigeot 4622c9916cdSFrançois Tigeot overlay->last_flip_req = NULL; 4632c9916cdSFrançois Tigeot overlay->old_xscale = 0; 4642c9916cdSFrançois Tigeot overlay->old_yscale = 0; 4652c9916cdSFrançois Tigeot overlay->crtc = NULL; 4662c9916cdSFrançois Tigeot overlay->active = false; 4672c9916cdSFrançois Tigeot } 4682c9916cdSFrançois Tigeot 469e3adcf8fSFrançois Tigeot struct put_image_params { 470e3adcf8fSFrançois Tigeot int format; 471e3adcf8fSFrançois Tigeot short dst_x; 472e3adcf8fSFrançois Tigeot short dst_y; 473e3adcf8fSFrançois Tigeot short dst_w; 474e3adcf8fSFrançois Tigeot short dst_h; 475e3adcf8fSFrançois Tigeot short src_w; 476e3adcf8fSFrançois Tigeot short src_scan_h; 477e3adcf8fSFrançois Tigeot short src_scan_w; 478e3adcf8fSFrançois Tigeot short src_h; 479e3adcf8fSFrançois Tigeot short stride_Y; 480e3adcf8fSFrançois Tigeot short stride_UV; 481e3adcf8fSFrançois Tigeot int offset_Y; 482e3adcf8fSFrançois Tigeot int offset_U; 483e3adcf8fSFrançois Tigeot int offset_V; 484e3adcf8fSFrançois Tigeot }; 485e3adcf8fSFrançois Tigeot 486e3adcf8fSFrançois Tigeot static int packed_depth_bytes(u32 format) 487e3adcf8fSFrançois Tigeot { 488e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 489e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 490e3adcf8fSFrançois Tigeot return 4; 491e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 492e3adcf8fSFrançois Tigeot /* return 6; not implemented */ 493e3adcf8fSFrançois Tigeot default: 494e3adcf8fSFrançois Tigeot return -EINVAL; 495e3adcf8fSFrançois Tigeot } 496e3adcf8fSFrançois Tigeot } 497e3adcf8fSFrançois Tigeot 498e3adcf8fSFrançois Tigeot static int packed_width_bytes(u32 format, short width) 499e3adcf8fSFrançois Tigeot { 500e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 501e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 502e3adcf8fSFrançois Tigeot return width << 1; 503e3adcf8fSFrançois Tigeot default: 504e3adcf8fSFrançois Tigeot return -EINVAL; 505e3adcf8fSFrançois Tigeot } 506e3adcf8fSFrançois Tigeot } 507e3adcf8fSFrançois Tigeot 508e3adcf8fSFrançois Tigeot static int uv_hsubsampling(u32 format) 509e3adcf8fSFrançois Tigeot { 510e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 511e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 512e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 513e3adcf8fSFrançois Tigeot return 2; 514e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 515e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 516e3adcf8fSFrançois Tigeot return 4; 517e3adcf8fSFrançois Tigeot default: 518e3adcf8fSFrançois Tigeot return -EINVAL; 519e3adcf8fSFrançois Tigeot } 520e3adcf8fSFrançois Tigeot } 521e3adcf8fSFrançois Tigeot 522e3adcf8fSFrançois Tigeot static int uv_vsubsampling(u32 format) 523e3adcf8fSFrançois Tigeot { 524e3adcf8fSFrançois Tigeot switch (format & I915_OVERLAY_DEPTH_MASK) { 525e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 526e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 527e3adcf8fSFrançois Tigeot return 2; 528e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 529e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 530e3adcf8fSFrançois Tigeot return 1; 531e3adcf8fSFrançois Tigeot default: 532e3adcf8fSFrançois Tigeot return -EINVAL; 533e3adcf8fSFrançois Tigeot } 534e3adcf8fSFrançois Tigeot } 535e3adcf8fSFrançois Tigeot 5361487f786SFrançois Tigeot static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width) 537e3adcf8fSFrançois Tigeot { 538e3adcf8fSFrançois Tigeot u32 mask, shift, ret; 5391487f786SFrançois Tigeot if (IS_GEN2(dev_priv)) { 540e3adcf8fSFrançois Tigeot mask = 0x1f; 541e3adcf8fSFrançois Tigeot shift = 5; 542e3adcf8fSFrançois Tigeot } else { 543e3adcf8fSFrançois Tigeot mask = 0x3f; 544e3adcf8fSFrançois Tigeot shift = 6; 545e3adcf8fSFrançois Tigeot } 546e3adcf8fSFrançois Tigeot ret = ((offset + width + mask) >> shift) - (offset >> shift); 5471487f786SFrançois Tigeot if (!IS_GEN2(dev_priv)) 548e3adcf8fSFrançois Tigeot ret <<= 1; 549e3adcf8fSFrançois Tigeot ret -= 1; 550e3adcf8fSFrançois Tigeot return ret << 2; 551e3adcf8fSFrançois Tigeot } 552e3adcf8fSFrançois Tigeot 553e3adcf8fSFrançois Tigeot static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { 554e3adcf8fSFrançois Tigeot 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0, 555e3adcf8fSFrançois Tigeot 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440, 556e3adcf8fSFrançois Tigeot 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0, 557e3adcf8fSFrançois Tigeot 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380, 558e3adcf8fSFrançois Tigeot 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320, 559e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0, 560e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260, 561e3adcf8fSFrançois Tigeot 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200, 562e3adcf8fSFrançois Tigeot 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0, 563e3adcf8fSFrançois Tigeot 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160, 564e3adcf8fSFrançois Tigeot 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120, 565e3adcf8fSFrançois Tigeot 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0, 566e3adcf8fSFrançois Tigeot 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0, 567e3adcf8fSFrançois Tigeot 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, 568e3adcf8fSFrançois Tigeot 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, 569e3adcf8fSFrançois Tigeot 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, 570e3adcf8fSFrançois Tigeot 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 571e3adcf8fSFrançois Tigeot }; 572e3adcf8fSFrançois Tigeot 573e3adcf8fSFrançois Tigeot static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { 574e3adcf8fSFrançois Tigeot 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, 575e3adcf8fSFrançois Tigeot 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, 576e3adcf8fSFrançois Tigeot 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880, 577e3adcf8fSFrançois Tigeot 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00, 578e3adcf8fSFrançois Tigeot 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0, 579e3adcf8fSFrançois Tigeot 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, 580e3adcf8fSFrançois Tigeot 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, 581e3adcf8fSFrançois Tigeot 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, 582e3adcf8fSFrançois Tigeot 0x3000, 0x0800, 0x3000 583e3adcf8fSFrançois Tigeot }; 584e3adcf8fSFrançois Tigeot 585e3440f96SFrançois Tigeot static void update_polyphase_filter(struct overlay_registers __iomem *regs) 586e3adcf8fSFrançois Tigeot { 587e3440f96SFrançois Tigeot memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs)); 588e3440f96SFrançois Tigeot memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs, 589e3440f96SFrançois Tigeot sizeof(uv_static_hcoeffs)); 590e3adcf8fSFrançois Tigeot } 591e3adcf8fSFrançois Tigeot 592e3adcf8fSFrançois Tigeot static bool update_scaling_factors(struct intel_overlay *overlay, 593e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs, 594e3adcf8fSFrançois Tigeot struct put_image_params *params) 595e3adcf8fSFrançois Tigeot { 596e3adcf8fSFrançois Tigeot /* fixed point with a 12 bit shift */ 597e3adcf8fSFrançois Tigeot u32 xscale, yscale, xscale_UV, yscale_UV; 598e3adcf8fSFrançois Tigeot #define FP_SHIFT 12 599e3adcf8fSFrançois Tigeot #define FRACT_MASK 0xfff 600e3adcf8fSFrançois Tigeot bool scale_changed = false; 601e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(params->format); 602e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(params->format); 603e3adcf8fSFrançois Tigeot 604e3adcf8fSFrançois Tigeot if (params->dst_w > 1) 605e3adcf8fSFrançois Tigeot xscale = ((params->src_scan_w - 1) << FP_SHIFT) 606e3adcf8fSFrançois Tigeot /(params->dst_w); 607e3adcf8fSFrançois Tigeot else 608e3adcf8fSFrançois Tigeot xscale = 1 << FP_SHIFT; 609e3adcf8fSFrançois Tigeot 610e3adcf8fSFrançois Tigeot if (params->dst_h > 1) 611e3adcf8fSFrançois Tigeot yscale = ((params->src_scan_h - 1) << FP_SHIFT) 612e3adcf8fSFrançois Tigeot /(params->dst_h); 613e3adcf8fSFrançois Tigeot else 614e3adcf8fSFrançois Tigeot yscale = 1 << FP_SHIFT; 615e3adcf8fSFrançois Tigeot 616e3adcf8fSFrançois Tigeot /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ 617e3adcf8fSFrançois Tigeot xscale_UV = xscale/uv_hscale; 618e3adcf8fSFrançois Tigeot yscale_UV = yscale/uv_vscale; 619e3adcf8fSFrançois Tigeot /* make the Y scale to UV scale ratio an exact multiply */ 620e3adcf8fSFrançois Tigeot xscale = xscale_UV * uv_hscale; 621e3adcf8fSFrançois Tigeot yscale = yscale_UV * uv_vscale; 622e3adcf8fSFrançois Tigeot /*} else { 623e3adcf8fSFrançois Tigeot xscale_UV = 0; 624e3adcf8fSFrançois Tigeot yscale_UV = 0; 625e3adcf8fSFrançois Tigeot }*/ 626e3adcf8fSFrançois Tigeot 627e3adcf8fSFrançois Tigeot if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) 628e3adcf8fSFrançois Tigeot scale_changed = true; 629e3adcf8fSFrançois Tigeot overlay->old_xscale = xscale; 630e3adcf8fSFrançois Tigeot overlay->old_yscale = yscale; 631e3adcf8fSFrançois Tigeot 632e3440f96SFrançois Tigeot iowrite32(((yscale & FRACT_MASK) << 20) | 633e3adcf8fSFrançois Tigeot ((xscale >> FP_SHIFT) << 16) | 634e3440f96SFrançois Tigeot ((xscale & FRACT_MASK) << 3), 635e3440f96SFrançois Tigeot ®s->YRGBSCALE); 636e3adcf8fSFrançois Tigeot 637e3440f96SFrançois Tigeot iowrite32(((yscale_UV & FRACT_MASK) << 20) | 638e3adcf8fSFrançois Tigeot ((xscale_UV >> FP_SHIFT) << 16) | 639e3440f96SFrançois Tigeot ((xscale_UV & FRACT_MASK) << 3), 640e3440f96SFrançois Tigeot ®s->UVSCALE); 641e3adcf8fSFrançois Tigeot 642e3440f96SFrançois Tigeot iowrite32((((yscale >> FP_SHIFT) << 16) | 643e3440f96SFrançois Tigeot ((yscale_UV >> FP_SHIFT) << 0)), 644e3440f96SFrançois Tigeot ®s->UVSCALEV); 645e3adcf8fSFrançois Tigeot 646e3adcf8fSFrançois Tigeot if (scale_changed) 647e3adcf8fSFrançois Tigeot update_polyphase_filter(regs); 648e3adcf8fSFrançois Tigeot 649e3adcf8fSFrançois Tigeot return scale_changed; 650e3adcf8fSFrançois Tigeot } 651e3adcf8fSFrançois Tigeot 652e3adcf8fSFrançois Tigeot static void update_colorkey(struct intel_overlay *overlay, 653e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 654e3adcf8fSFrançois Tigeot { 655e3adcf8fSFrançois Tigeot u32 key = overlay->color_key; 65619c468b4SFrançois Tigeot u32 flags; 65719c468b4SFrançois Tigeot 65819c468b4SFrançois Tigeot flags = 0; 65919c468b4SFrançois Tigeot if (overlay->color_key_enabled) 66019c468b4SFrançois Tigeot flags |= DST_KEY_ENABLE; 661e3adcf8fSFrançois Tigeot 662ba55f2f5SFrançois Tigeot switch (overlay->crtc->base.primary->fb->bits_per_pixel) { 663e3adcf8fSFrançois Tigeot case 8: 66419c468b4SFrançois Tigeot key = 0; 66519c468b4SFrançois Tigeot flags |= CLK_RGB8I_MASK; 666e3adcf8fSFrançois Tigeot break; 667e3adcf8fSFrançois Tigeot 668e3adcf8fSFrançois Tigeot case 16: 669ba55f2f5SFrançois Tigeot if (overlay->crtc->base.primary->fb->depth == 15) { 67019c468b4SFrançois Tigeot key = RGB15_TO_COLORKEY(key); 67119c468b4SFrançois Tigeot flags |= CLK_RGB15_MASK; 672e3adcf8fSFrançois Tigeot } else { 67319c468b4SFrançois Tigeot key = RGB16_TO_COLORKEY(key); 67419c468b4SFrançois Tigeot flags |= CLK_RGB16_MASK; 675e3adcf8fSFrançois Tigeot } 676e3adcf8fSFrançois Tigeot break; 677e3adcf8fSFrançois Tigeot 678e3adcf8fSFrançois Tigeot case 24: 679e3adcf8fSFrançois Tigeot case 32: 68019c468b4SFrançois Tigeot flags |= CLK_RGB24_MASK; 681e3adcf8fSFrançois Tigeot break; 682e3adcf8fSFrançois Tigeot } 68319c468b4SFrançois Tigeot 68419c468b4SFrançois Tigeot iowrite32(key, ®s->DCLRKV); 68519c468b4SFrançois Tigeot iowrite32(flags, ®s->DCLRKM); 686e3adcf8fSFrançois Tigeot } 687e3adcf8fSFrançois Tigeot 688e3adcf8fSFrançois Tigeot static u32 overlay_cmd_reg(struct put_image_params *params) 689e3adcf8fSFrançois Tigeot { 690e3adcf8fSFrançois Tigeot u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0; 691e3adcf8fSFrançois Tigeot 692e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PLANAR) { 693e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_DEPTH_MASK) { 694e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 695e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_422_PLANAR; 696e3adcf8fSFrançois Tigeot break; 697e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV420: 698e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_420_PLANAR; 699e3adcf8fSFrançois Tigeot break; 700e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 701e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV410: 702e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_410_PLANAR; 703e3adcf8fSFrançois Tigeot break; 704e3adcf8fSFrançois Tigeot } 705e3adcf8fSFrançois Tigeot } else { /* YUV packed */ 706e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_DEPTH_MASK) { 707e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV422: 708e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_422_PACKED; 709e3adcf8fSFrançois Tigeot break; 710e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV411: 711e3adcf8fSFrançois Tigeot cmd |= OCMD_YUV_411_PACKED; 712e3adcf8fSFrançois Tigeot break; 713e3adcf8fSFrançois Tigeot } 714e3adcf8fSFrançois Tigeot 715e3adcf8fSFrançois Tigeot switch (params->format & I915_OVERLAY_SWAP_MASK) { 716e3adcf8fSFrançois Tigeot case I915_OVERLAY_NO_SWAP: 717e3adcf8fSFrançois Tigeot break; 718e3adcf8fSFrançois Tigeot case I915_OVERLAY_UV_SWAP: 719e3adcf8fSFrançois Tigeot cmd |= OCMD_UV_SWAP; 720e3adcf8fSFrançois Tigeot break; 721e3adcf8fSFrançois Tigeot case I915_OVERLAY_Y_SWAP: 722e3adcf8fSFrançois Tigeot cmd |= OCMD_Y_SWAP; 723e3adcf8fSFrançois Tigeot break; 724e3adcf8fSFrançois Tigeot case I915_OVERLAY_Y_AND_UV_SWAP: 725e3adcf8fSFrançois Tigeot cmd |= OCMD_Y_AND_UV_SWAP; 726e3adcf8fSFrançois Tigeot break; 727e3adcf8fSFrançois Tigeot } 728e3adcf8fSFrançois Tigeot } 729e3adcf8fSFrançois Tigeot 730e3adcf8fSFrançois Tigeot return cmd; 731e3adcf8fSFrançois Tigeot } 732e3adcf8fSFrançois Tigeot 733e3adcf8fSFrançois Tigeot static int intel_overlay_do_put_image(struct intel_overlay *overlay, 734e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo, 735e3adcf8fSFrançois Tigeot struct put_image_params *params) 736e3adcf8fSFrançois Tigeot { 737e3adcf8fSFrançois Tigeot int ret, tmp_width; 738e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 739e3adcf8fSFrançois Tigeot bool scale_changed = false; 7401487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 741e3440f96SFrançois Tigeot u32 swidth, swidthsw, sheight, ostride; 74224edb884SFrançois Tigeot enum i915_pipe pipe = overlay->crtc->pipe; 743e3adcf8fSFrançois Tigeot 744303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex); 745303bf270SFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex)); 746e3adcf8fSFrançois Tigeot 747e3adcf8fSFrançois Tigeot ret = intel_overlay_release_old_vid(overlay); 748e3adcf8fSFrançois Tigeot if (ret != 0) 749e3adcf8fSFrançois Tigeot return ret; 750e3adcf8fSFrançois Tigeot 751aee94f86SFrançois Tigeot ret = i915_gem_object_pin_to_display_plane(new_bo, 0, 752477eb7f9SFrançois Tigeot &i915_ggtt_view_normal); 753e3adcf8fSFrançois Tigeot if (ret != 0) 754e3440f96SFrançois Tigeot return ret; 755e3adcf8fSFrançois Tigeot 756e3adcf8fSFrançois Tigeot ret = i915_gem_object_put_fence(new_bo); 757e3adcf8fSFrançois Tigeot if (ret) 758e3adcf8fSFrançois Tigeot goto out_unpin; 759e3adcf8fSFrançois Tigeot 760e3adcf8fSFrançois Tigeot if (!overlay->active) { 761e3440f96SFrançois Tigeot u32 oconfig; 762e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 763e3adcf8fSFrançois Tigeot if (!regs) { 764e3adcf8fSFrançois Tigeot ret = -ENOMEM; 765e3adcf8fSFrançois Tigeot goto out_unpin; 766e3adcf8fSFrançois Tigeot } 767e3440f96SFrançois Tigeot oconfig = OCONF_CC_OUT_8BIT; 7681487f786SFrançois Tigeot if (IS_GEN4(dev_priv)) 769e3440f96SFrançois Tigeot oconfig |= OCONF_CSC_MODE_BT709; 77024edb884SFrançois Tigeot oconfig |= pipe == 0 ? 771e3adcf8fSFrançois Tigeot OCONF_PIPE_A : OCONF_PIPE_B; 772e3440f96SFrançois Tigeot iowrite32(oconfig, ®s->OCONFIG); 773e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 774e3adcf8fSFrançois Tigeot 775e3adcf8fSFrançois Tigeot ret = intel_overlay_on(overlay); 776e3adcf8fSFrançois Tigeot if (ret != 0) 777e3adcf8fSFrançois Tigeot goto out_unpin; 778e3adcf8fSFrançois Tigeot } 779e3adcf8fSFrançois Tigeot 780e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 781e3adcf8fSFrançois Tigeot if (!regs) { 782e3adcf8fSFrançois Tigeot ret = -ENOMEM; 783e3adcf8fSFrançois Tigeot goto out_unpin; 784e3adcf8fSFrançois Tigeot } 785e3adcf8fSFrançois Tigeot 786e3440f96SFrançois Tigeot iowrite32((params->dst_y << 16) | params->dst_x, ®s->DWINPOS); 787e3440f96SFrançois Tigeot iowrite32((params->dst_h << 16) | params->dst_w, ®s->DWINSZ); 788e3adcf8fSFrançois Tigeot 789e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PACKED) 790e3adcf8fSFrançois Tigeot tmp_width = packed_width_bytes(params->format, params->src_w); 791e3adcf8fSFrançois Tigeot else 792e3adcf8fSFrançois Tigeot tmp_width = params->src_w; 793e3adcf8fSFrançois Tigeot 794e3440f96SFrançois Tigeot swidth = params->src_w; 7951487f786SFrançois Tigeot swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width); 796e3440f96SFrançois Tigeot sheight = params->src_h; 7979edbd4a0SFrançois Tigeot iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, ®s->OBUF_0Y); 798e3440f96SFrançois Tigeot ostride = params->stride_Y; 799e3adcf8fSFrançois Tigeot 800e3adcf8fSFrançois Tigeot if (params->format & I915_OVERLAY_YUV_PLANAR) { 801e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(params->format); 802e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(params->format); 803e3adcf8fSFrançois Tigeot u32 tmp_U, tmp_V; 804e3440f96SFrançois Tigeot swidth |= (params->src_w/uv_hscale) << 16; 8051487f786SFrançois Tigeot tmp_U = calc_swidthsw(dev_priv, params->offset_U, 806e3adcf8fSFrançois Tigeot params->src_w/uv_hscale); 8071487f786SFrançois Tigeot tmp_V = calc_swidthsw(dev_priv, params->offset_V, 808e3adcf8fSFrançois Tigeot params->src_w/uv_hscale); 809e3440f96SFrançois Tigeot swidthsw |= max_t(u32, tmp_U, tmp_V) << 16; 810e3440f96SFrançois Tigeot sheight |= (params->src_h/uv_vscale) << 16; 8119edbd4a0SFrançois Tigeot iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, ®s->OBUF_0U); 8129edbd4a0SFrançois Tigeot iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, ®s->OBUF_0V); 813e3440f96SFrançois Tigeot ostride |= params->stride_UV << 16; 814e3adcf8fSFrançois Tigeot } 815e3adcf8fSFrançois Tigeot 816e3440f96SFrançois Tigeot iowrite32(swidth, ®s->SWIDTH); 817e3440f96SFrançois Tigeot iowrite32(swidthsw, ®s->SWIDTHSW); 818e3440f96SFrançois Tigeot iowrite32(sheight, ®s->SHEIGHT); 819e3440f96SFrançois Tigeot iowrite32(ostride, ®s->OSTRIDE); 820e3440f96SFrançois Tigeot 821e3adcf8fSFrançois Tigeot scale_changed = update_scaling_factors(overlay, regs, params); 822e3adcf8fSFrançois Tigeot 823e3adcf8fSFrançois Tigeot update_colorkey(overlay, regs); 824e3adcf8fSFrançois Tigeot 825e3440f96SFrançois Tigeot iowrite32(overlay_cmd_reg(params), ®s->OCMD); 826e3adcf8fSFrançois Tigeot 827e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 828e3adcf8fSFrançois Tigeot 829e3adcf8fSFrançois Tigeot ret = intel_overlay_continue(overlay, scale_changed); 830e3adcf8fSFrançois Tigeot if (ret) 831e3adcf8fSFrançois Tigeot goto out_unpin; 832e3adcf8fSFrançois Tigeot 83324edb884SFrançois Tigeot i915_gem_track_fb(overlay->vid_bo, new_bo, 83424edb884SFrançois Tigeot INTEL_FRONTBUFFER_OVERLAY(pipe)); 83524edb884SFrançois Tigeot 836e3adcf8fSFrançois Tigeot overlay->old_vid_bo = overlay->vid_bo; 837e3adcf8fSFrançois Tigeot overlay->vid_bo = new_bo; 838e3adcf8fSFrançois Tigeot 839303bf270SFrançois Tigeot intel_frontbuffer_flip(&dev_priv->drm, 840303bf270SFrançois Tigeot INTEL_FRONTBUFFER_OVERLAY(pipe)); 84124edb884SFrançois Tigeot 842e3adcf8fSFrançois Tigeot return 0; 843e3adcf8fSFrançois Tigeot 844e3adcf8fSFrançois Tigeot out_unpin: 845ba55f2f5SFrançois Tigeot i915_gem_object_ggtt_unpin(new_bo); 846e3adcf8fSFrançois Tigeot return ret; 847e3adcf8fSFrançois Tigeot } 848e3adcf8fSFrançois Tigeot 849e3adcf8fSFrançois Tigeot int intel_overlay_switch_off(struct intel_overlay *overlay) 850e3adcf8fSFrançois Tigeot { 8511487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 852e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 853e3adcf8fSFrançois Tigeot int ret; 854e3adcf8fSFrançois Tigeot 855303bf270SFrançois Tigeot lockdep_assert_held(&dev_priv->drm.struct_mutex); 856303bf270SFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex)); 857e3adcf8fSFrançois Tigeot 858e3adcf8fSFrançois Tigeot ret = intel_overlay_recover_from_interrupt(overlay); 859e3adcf8fSFrançois Tigeot if (ret != 0) 860e3adcf8fSFrançois Tigeot return ret; 861e3adcf8fSFrançois Tigeot 862e3adcf8fSFrançois Tigeot if (!overlay->active) 863e3adcf8fSFrançois Tigeot return 0; 864e3adcf8fSFrançois Tigeot 865e3adcf8fSFrançois Tigeot ret = intel_overlay_release_old_vid(overlay); 866e3adcf8fSFrançois Tigeot if (ret != 0) 867e3adcf8fSFrançois Tigeot return ret; 868e3adcf8fSFrançois Tigeot 869e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 870e3440f96SFrançois Tigeot iowrite32(0, ®s->OCMD); 871e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 872e3adcf8fSFrançois Tigeot 873e3adcf8fSFrançois Tigeot ret = intel_overlay_off(overlay); 874e3adcf8fSFrançois Tigeot if (ret != 0) 875e3adcf8fSFrançois Tigeot return ret; 876e3adcf8fSFrançois Tigeot 877e3adcf8fSFrançois Tigeot intel_overlay_off_tail(overlay); 878e3adcf8fSFrançois Tigeot return 0; 879e3adcf8fSFrançois Tigeot } 880e3adcf8fSFrançois Tigeot 881e3adcf8fSFrançois Tigeot static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, 882e3adcf8fSFrançois Tigeot struct intel_crtc *crtc) 883e3adcf8fSFrançois Tigeot { 884e3adcf8fSFrançois Tigeot if (!crtc->active) 885e3adcf8fSFrançois Tigeot return -EINVAL; 886e3adcf8fSFrançois Tigeot 887e3adcf8fSFrançois Tigeot /* can't use the overlay with double wide pipe */ 8882c9916cdSFrançois Tigeot if (crtc->config->double_wide) 889e3adcf8fSFrançois Tigeot return -EINVAL; 890e3adcf8fSFrançois Tigeot 891e3adcf8fSFrançois Tigeot return 0; 892e3adcf8fSFrançois Tigeot } 893e3adcf8fSFrançois Tigeot 894e3adcf8fSFrançois Tigeot static void update_pfit_vscale_ratio(struct intel_overlay *overlay) 895e3adcf8fSFrançois Tigeot { 8961487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 897e3adcf8fSFrançois Tigeot u32 pfit_control = I915_READ(PFIT_CONTROL); 898e3adcf8fSFrançois Tigeot u32 ratio; 899e3adcf8fSFrançois Tigeot 900e3adcf8fSFrançois Tigeot /* XXX: This is not the same logic as in the xorg driver, but more in 901e3adcf8fSFrançois Tigeot * line with the intel documentation for the i965 902e3adcf8fSFrançois Tigeot */ 9031487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 4) { 904e3adcf8fSFrançois Tigeot /* on i965 use the PGM reg to read out the autoscaler values */ 905e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; 906e3adcf8fSFrançois Tigeot } else { 907e3adcf8fSFrançois Tigeot if (pfit_control & VERT_AUTO_SCALE) 908e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_AUTO_RATIOS); 909e3adcf8fSFrançois Tigeot else 910e3adcf8fSFrançois Tigeot ratio = I915_READ(PFIT_PGM_RATIOS); 911e3adcf8fSFrançois Tigeot ratio >>= PFIT_VERT_SCALE_SHIFT; 912e3adcf8fSFrançois Tigeot } 913e3adcf8fSFrançois Tigeot 914e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio = ratio; 915e3adcf8fSFrançois Tigeot } 916e3adcf8fSFrançois Tigeot 917e3adcf8fSFrançois Tigeot static int check_overlay_dst(struct intel_overlay *overlay, 918e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *rec) 919e3adcf8fSFrançois Tigeot { 920e3adcf8fSFrançois Tigeot struct drm_display_mode *mode = &overlay->crtc->base.mode; 921e3adcf8fSFrançois Tigeot 922e3adcf8fSFrançois Tigeot if (rec->dst_x < mode->hdisplay && 923e3adcf8fSFrançois Tigeot rec->dst_x + rec->dst_width <= mode->hdisplay && 924e3adcf8fSFrançois Tigeot rec->dst_y < mode->vdisplay && 925e3adcf8fSFrançois Tigeot rec->dst_y + rec->dst_height <= mode->vdisplay) 926e3adcf8fSFrançois Tigeot return 0; 927e3adcf8fSFrançois Tigeot else 928e3adcf8fSFrançois Tigeot return -EINVAL; 929e3adcf8fSFrançois Tigeot } 930e3adcf8fSFrançois Tigeot 931e3adcf8fSFrançois Tigeot static int check_overlay_scaling(struct put_image_params *rec) 932e3adcf8fSFrançois Tigeot { 933e3adcf8fSFrançois Tigeot u32 tmp; 934e3adcf8fSFrançois Tigeot 935e3adcf8fSFrançois Tigeot /* downscaling limit is 8.0 */ 936e3adcf8fSFrançois Tigeot tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16; 937e3adcf8fSFrançois Tigeot if (tmp > 7) 938e3adcf8fSFrançois Tigeot return -EINVAL; 939e3adcf8fSFrançois Tigeot tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16; 940e3adcf8fSFrançois Tigeot if (tmp > 7) 941e3adcf8fSFrançois Tigeot return -EINVAL; 942e3adcf8fSFrançois Tigeot 943e3adcf8fSFrançois Tigeot return 0; 944e3adcf8fSFrançois Tigeot } 945e3adcf8fSFrançois Tigeot 9461487f786SFrançois Tigeot static int check_overlay_src(struct drm_i915_private *dev_priv, 947e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *rec, 948e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo) 949e3adcf8fSFrançois Tigeot { 950e3adcf8fSFrançois Tigeot int uv_hscale = uv_hsubsampling(rec->flags); 951e3adcf8fSFrançois Tigeot int uv_vscale = uv_vsubsampling(rec->flags); 952e3adcf8fSFrançois Tigeot u32 stride_mask; 953e3adcf8fSFrançois Tigeot int depth; 954e3adcf8fSFrançois Tigeot u32 tmp; 955e3adcf8fSFrançois Tigeot 956e3adcf8fSFrançois Tigeot /* check src dimensions */ 9571487f786SFrançois Tigeot if (IS_845G(dev_priv) || IS_I830(dev_priv)) { 958e3adcf8fSFrançois Tigeot if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || 959e3adcf8fSFrançois Tigeot rec->src_width > IMAGE_MAX_WIDTH_LEGACY) 960e3adcf8fSFrançois Tigeot return -EINVAL; 961e3adcf8fSFrançois Tigeot } else { 962e3adcf8fSFrançois Tigeot if (rec->src_height > IMAGE_MAX_HEIGHT || 963e3adcf8fSFrançois Tigeot rec->src_width > IMAGE_MAX_WIDTH) 964e3adcf8fSFrançois Tigeot return -EINVAL; 965e3adcf8fSFrançois Tigeot } 966e3adcf8fSFrançois Tigeot 967e3adcf8fSFrançois Tigeot /* better safe than sorry, use 4 as the maximal subsampling ratio */ 968e3adcf8fSFrançois Tigeot if (rec->src_height < N_VERT_Y_TAPS*4 || 969e3adcf8fSFrançois Tigeot rec->src_width < N_HORIZ_Y_TAPS*4) 970e3adcf8fSFrançois Tigeot return -EINVAL; 971e3adcf8fSFrançois Tigeot 972e3adcf8fSFrançois Tigeot /* check alignment constraints */ 973e3adcf8fSFrançois Tigeot switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 974e3adcf8fSFrançois Tigeot case I915_OVERLAY_RGB: 975e3adcf8fSFrançois Tigeot /* not implemented */ 976e3adcf8fSFrançois Tigeot return -EINVAL; 977e3adcf8fSFrançois Tigeot 978e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PACKED: 979e3adcf8fSFrançois Tigeot if (uv_vscale != 1) 980e3adcf8fSFrançois Tigeot return -EINVAL; 981e3adcf8fSFrançois Tigeot 982e3adcf8fSFrançois Tigeot depth = packed_depth_bytes(rec->flags); 983e3adcf8fSFrançois Tigeot if (depth < 0) 984e3adcf8fSFrançois Tigeot return depth; 985e3adcf8fSFrançois Tigeot 986e3adcf8fSFrançois Tigeot /* ignore UV planes */ 987e3adcf8fSFrançois Tigeot rec->stride_UV = 0; 988e3adcf8fSFrançois Tigeot rec->offset_U = 0; 989e3adcf8fSFrançois Tigeot rec->offset_V = 0; 990e3adcf8fSFrançois Tigeot /* check pixel alignment */ 991e3adcf8fSFrançois Tigeot if (rec->offset_Y % depth) 992e3adcf8fSFrançois Tigeot return -EINVAL; 993e3adcf8fSFrançois Tigeot break; 994e3adcf8fSFrançois Tigeot 995e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PLANAR: 996e3adcf8fSFrançois Tigeot if (uv_vscale < 0 || uv_hscale < 0) 997e3adcf8fSFrançois Tigeot return -EINVAL; 998e3adcf8fSFrançois Tigeot /* no offset restrictions for planar formats */ 999e3adcf8fSFrançois Tigeot break; 1000e3adcf8fSFrançois Tigeot 1001e3adcf8fSFrançois Tigeot default: 1002e3adcf8fSFrançois Tigeot return -EINVAL; 1003e3adcf8fSFrançois Tigeot } 1004e3adcf8fSFrançois Tigeot 1005e3adcf8fSFrançois Tigeot if (rec->src_width % uv_hscale) 1006e3adcf8fSFrançois Tigeot return -EINVAL; 1007e3adcf8fSFrançois Tigeot 1008e3adcf8fSFrançois Tigeot /* stride checking */ 10091487f786SFrançois Tigeot if (IS_I830(dev_priv) || IS_845G(dev_priv)) 1010e3adcf8fSFrançois Tigeot stride_mask = 255; 1011e3adcf8fSFrançois Tigeot else 1012e3adcf8fSFrançois Tigeot stride_mask = 63; 1013e3adcf8fSFrançois Tigeot 1014e3adcf8fSFrançois Tigeot if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) 1015e3adcf8fSFrançois Tigeot return -EINVAL; 10161487f786SFrançois Tigeot if (IS_GEN4(dev_priv) && rec->stride_Y < 512) 1017e3adcf8fSFrançois Tigeot return -EINVAL; 1018e3adcf8fSFrançois Tigeot 1019e3adcf8fSFrançois Tigeot tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? 1020e3adcf8fSFrançois Tigeot 4096 : 8192; 1021e3adcf8fSFrançois Tigeot if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) 1022e3adcf8fSFrançois Tigeot return -EINVAL; 1023e3adcf8fSFrançois Tigeot 1024e3adcf8fSFrançois Tigeot /* check buffer dimensions */ 1025e3adcf8fSFrançois Tigeot switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 1026e3adcf8fSFrançois Tigeot case I915_OVERLAY_RGB: 1027e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PACKED: 1028e3adcf8fSFrançois Tigeot /* always 4 Y values per depth pixels */ 1029e3adcf8fSFrançois Tigeot if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) 1030e3adcf8fSFrançois Tigeot return -EINVAL; 1031e3adcf8fSFrançois Tigeot 1032e3adcf8fSFrançois Tigeot tmp = rec->stride_Y*rec->src_height; 1033e3adcf8fSFrançois Tigeot if (rec->offset_Y + tmp > new_bo->base.size) 1034e3adcf8fSFrançois Tigeot return -EINVAL; 1035e3adcf8fSFrançois Tigeot break; 1036e3adcf8fSFrançois Tigeot 1037e3adcf8fSFrançois Tigeot case I915_OVERLAY_YUV_PLANAR: 1038e3adcf8fSFrançois Tigeot if (rec->src_width > rec->stride_Y) 1039e3adcf8fSFrançois Tigeot return -EINVAL; 1040e3adcf8fSFrançois Tigeot if (rec->src_width/uv_hscale > rec->stride_UV) 1041e3adcf8fSFrançois Tigeot return -EINVAL; 1042e3adcf8fSFrançois Tigeot 1043e3adcf8fSFrançois Tigeot tmp = rec->stride_Y * rec->src_height; 1044e3adcf8fSFrançois Tigeot if (rec->offset_Y + tmp > new_bo->base.size) 1045e3adcf8fSFrançois Tigeot return -EINVAL; 1046e3adcf8fSFrançois Tigeot 1047e3adcf8fSFrançois Tigeot tmp = rec->stride_UV * (rec->src_height / uv_vscale); 1048e3adcf8fSFrançois Tigeot if (rec->offset_U + tmp > new_bo->base.size || 1049e3adcf8fSFrançois Tigeot rec->offset_V + tmp > new_bo->base.size) 1050e3adcf8fSFrançois Tigeot return -EINVAL; 1051e3adcf8fSFrançois Tigeot break; 1052e3adcf8fSFrançois Tigeot } 1053e3adcf8fSFrançois Tigeot 1054e3adcf8fSFrançois Tigeot return 0; 1055e3adcf8fSFrançois Tigeot } 1056e3adcf8fSFrançois Tigeot 1057e3adcf8fSFrançois Tigeot /** 1058e3adcf8fSFrançois Tigeot * Return the pipe currently connected to the panel fitter, 1059e3adcf8fSFrançois Tigeot * or -1 if the panel fitter is not present or not in use 1060e3adcf8fSFrançois Tigeot */ 10611487f786SFrançois Tigeot static int intel_panel_fitter_pipe(struct drm_i915_private *dev_priv) 1062e3adcf8fSFrançois Tigeot { 1063e3adcf8fSFrançois Tigeot u32 pfit_control; 1064e3adcf8fSFrançois Tigeot 1065e3adcf8fSFrançois Tigeot /* i830 doesn't have a panel fitter */ 10661487f786SFrançois Tigeot if (INTEL_GEN(dev_priv) <= 3 && 10671487f786SFrançois Tigeot (IS_I830(dev_priv) || !IS_MOBILE(dev_priv))) 1068e3adcf8fSFrançois Tigeot return -1; 1069e3adcf8fSFrançois Tigeot 1070e3adcf8fSFrançois Tigeot pfit_control = I915_READ(PFIT_CONTROL); 1071e3adcf8fSFrançois Tigeot 1072e3adcf8fSFrançois Tigeot /* See if the panel fitter is in use */ 1073e3adcf8fSFrançois Tigeot if ((pfit_control & PFIT_ENABLE) == 0) 1074e3adcf8fSFrançois Tigeot return -1; 1075e3adcf8fSFrançois Tigeot 1076e3adcf8fSFrançois Tigeot /* 965 can place panel fitter on either pipe */ 10771487f786SFrançois Tigeot if (IS_GEN4(dev_priv)) 1078e3adcf8fSFrançois Tigeot return (pfit_control >> 29) & 0x3; 1079e3adcf8fSFrançois Tigeot 1080e3adcf8fSFrançois Tigeot /* older chips can only use pipe 1 */ 1081e3adcf8fSFrançois Tigeot return 1; 1082e3adcf8fSFrançois Tigeot } 1083e3adcf8fSFrançois Tigeot 10841487f786SFrançois Tigeot int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, 1085e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1086e3adcf8fSFrançois Tigeot { 1087e3adcf8fSFrançois Tigeot struct drm_intel_overlay_put_image *put_image_rec = data; 1088*bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1089e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 109024edb884SFrançois Tigeot struct drm_crtc *drmmode_crtc; 1091e3adcf8fSFrançois Tigeot struct intel_crtc *crtc; 1092e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *new_bo; 1093e3adcf8fSFrançois Tigeot struct put_image_params *params; 1094e3adcf8fSFrançois Tigeot int ret; 1095e3adcf8fSFrançois Tigeot 1096e3adcf8fSFrançois Tigeot overlay = dev_priv->overlay; 1097e3adcf8fSFrançois Tigeot if (!overlay) { 1098e3adcf8fSFrançois Tigeot DRM_DEBUG("userspace bug: no overlay\n"); 1099e3adcf8fSFrançois Tigeot return -ENODEV; 1100e3adcf8fSFrançois Tigeot } 1101e3adcf8fSFrançois Tigeot 1102e3adcf8fSFrançois Tigeot if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { 1103a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1104a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1105e3adcf8fSFrançois Tigeot 1106e3adcf8fSFrançois Tigeot ret = intel_overlay_switch_off(overlay); 1107e3adcf8fSFrançois Tigeot 1108a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1109a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1110e3adcf8fSFrançois Tigeot 1111e3adcf8fSFrançois Tigeot return ret; 1112e3adcf8fSFrançois Tigeot } 1113e3adcf8fSFrançois Tigeot 1114*bf017597SFrançois Tigeot params = kmalloc(sizeof(*params), M_DRM, GFP_KERNEL); 1115e3440f96SFrançois Tigeot if (!params) 1116e3440f96SFrançois Tigeot return -ENOMEM; 1117e3adcf8fSFrançois Tigeot 111824edb884SFrançois Tigeot drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id); 111924edb884SFrançois Tigeot if (!drmmode_crtc) { 1120e3adcf8fSFrançois Tigeot ret = -ENOENT; 1121e3adcf8fSFrançois Tigeot goto out_free; 1122e3adcf8fSFrançois Tigeot } 112324edb884SFrançois Tigeot crtc = to_intel_crtc(drmmode_crtc); 1124e3adcf8fSFrançois Tigeot 11258621f407SFrançois Tigeot new_bo = to_intel_bo(drm_gem_object_lookup(file_priv, 1126e3adcf8fSFrançois Tigeot put_image_rec->bo_handle)); 1127e3adcf8fSFrançois Tigeot if (&new_bo->base == NULL) { 1128e3adcf8fSFrançois Tigeot ret = -ENOENT; 1129e3adcf8fSFrançois Tigeot goto out_free; 1130e3adcf8fSFrançois Tigeot } 1131e3adcf8fSFrançois Tigeot 1132a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1133a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1134e3adcf8fSFrançois Tigeot 1135e3adcf8fSFrançois Tigeot if (new_bo->tiling_mode) { 1136ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n"); 1137e3adcf8fSFrançois Tigeot ret = -EINVAL; 1138e3adcf8fSFrançois Tigeot goto out_unlock; 1139e3adcf8fSFrançois Tigeot } 1140e3adcf8fSFrançois Tigeot 1141e3adcf8fSFrançois Tigeot ret = intel_overlay_recover_from_interrupt(overlay); 1142e3adcf8fSFrançois Tigeot if (ret != 0) 1143e3adcf8fSFrançois Tigeot goto out_unlock; 1144e3adcf8fSFrançois Tigeot 1145e3adcf8fSFrançois Tigeot if (overlay->crtc != crtc) { 1146e3adcf8fSFrançois Tigeot struct drm_display_mode *mode = &crtc->base.mode; 1147e3adcf8fSFrançois Tigeot ret = intel_overlay_switch_off(overlay); 1148e3adcf8fSFrançois Tigeot if (ret != 0) 1149e3adcf8fSFrançois Tigeot goto out_unlock; 1150e3adcf8fSFrançois Tigeot 1151e3adcf8fSFrançois Tigeot ret = check_overlay_possible_on_crtc(overlay, crtc); 1152e3adcf8fSFrançois Tigeot if (ret != 0) 1153e3adcf8fSFrançois Tigeot goto out_unlock; 1154e3adcf8fSFrançois Tigeot 1155e3adcf8fSFrançois Tigeot overlay->crtc = crtc; 1156e3adcf8fSFrançois Tigeot crtc->overlay = overlay; 1157e3adcf8fSFrançois Tigeot 1158e3adcf8fSFrançois Tigeot /* line too wide, i.e. one-line-mode */ 1159e3adcf8fSFrançois Tigeot if (mode->hdisplay > 1024 && 11601487f786SFrançois Tigeot intel_panel_fitter_pipe(dev_priv) == crtc->pipe) { 116119c468b4SFrançois Tigeot overlay->pfit_active = true; 1162e3adcf8fSFrançois Tigeot update_pfit_vscale_ratio(overlay); 1163e3adcf8fSFrançois Tigeot } else 116419c468b4SFrançois Tigeot overlay->pfit_active = false; 1165e3adcf8fSFrançois Tigeot } 1166e3adcf8fSFrançois Tigeot 1167e3adcf8fSFrançois Tigeot ret = check_overlay_dst(overlay, put_image_rec); 1168e3adcf8fSFrançois Tigeot if (ret != 0) 1169e3adcf8fSFrançois Tigeot goto out_unlock; 1170e3adcf8fSFrançois Tigeot 1171e3adcf8fSFrançois Tigeot if (overlay->pfit_active) { 1172e3adcf8fSFrançois Tigeot params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / 1173e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio); 1174e3adcf8fSFrançois Tigeot /* shifting right rounds downwards, so add 1 */ 1175e3adcf8fSFrançois Tigeot params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / 1176e3adcf8fSFrançois Tigeot overlay->pfit_vscale_ratio) + 1; 1177e3adcf8fSFrançois Tigeot } else { 1178e3adcf8fSFrançois Tigeot params->dst_y = put_image_rec->dst_y; 1179e3adcf8fSFrançois Tigeot params->dst_h = put_image_rec->dst_height; 1180e3adcf8fSFrançois Tigeot } 1181e3adcf8fSFrançois Tigeot params->dst_x = put_image_rec->dst_x; 1182e3adcf8fSFrançois Tigeot params->dst_w = put_image_rec->dst_width; 1183e3adcf8fSFrançois Tigeot 1184e3adcf8fSFrançois Tigeot params->src_w = put_image_rec->src_width; 1185e3adcf8fSFrançois Tigeot params->src_h = put_image_rec->src_height; 1186e3adcf8fSFrançois Tigeot params->src_scan_w = put_image_rec->src_scan_width; 1187e3adcf8fSFrançois Tigeot params->src_scan_h = put_image_rec->src_scan_height; 1188e3adcf8fSFrançois Tigeot if (params->src_scan_h > params->src_h || 1189e3adcf8fSFrançois Tigeot params->src_scan_w > params->src_w) { 1190e3adcf8fSFrançois Tigeot ret = -EINVAL; 1191e3adcf8fSFrançois Tigeot goto out_unlock; 1192e3adcf8fSFrançois Tigeot } 1193e3adcf8fSFrançois Tigeot 11941487f786SFrançois Tigeot ret = check_overlay_src(dev_priv, put_image_rec, new_bo); 1195e3adcf8fSFrançois Tigeot if (ret != 0) 1196e3adcf8fSFrançois Tigeot goto out_unlock; 1197e3adcf8fSFrançois Tigeot params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK; 1198e3adcf8fSFrançois Tigeot params->stride_Y = put_image_rec->stride_Y; 1199e3adcf8fSFrançois Tigeot params->stride_UV = put_image_rec->stride_UV; 1200e3adcf8fSFrançois Tigeot params->offset_Y = put_image_rec->offset_Y; 1201e3adcf8fSFrançois Tigeot params->offset_U = put_image_rec->offset_U; 1202e3adcf8fSFrançois Tigeot params->offset_V = put_image_rec->offset_V; 1203e3adcf8fSFrançois Tigeot 1204e3adcf8fSFrançois Tigeot /* Check scaling after src size to prevent a divide-by-zero. */ 1205e3adcf8fSFrançois Tigeot ret = check_overlay_scaling(params); 1206e3adcf8fSFrançois Tigeot if (ret != 0) 1207e3adcf8fSFrançois Tigeot goto out_unlock; 1208e3adcf8fSFrançois Tigeot 1209e3adcf8fSFrançois Tigeot ret = intel_overlay_do_put_image(overlay, new_bo, params); 1210e3adcf8fSFrançois Tigeot if (ret != 0) 1211e3adcf8fSFrançois Tigeot goto out_unlock; 1212e3adcf8fSFrançois Tigeot 1213a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1214a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1215e3adcf8fSFrançois Tigeot 1216158486a6SFrançois Tigeot kfree(params); 1217e3adcf8fSFrançois Tigeot 1218e3adcf8fSFrançois Tigeot return 0; 1219e3adcf8fSFrançois Tigeot 1220e3adcf8fSFrançois Tigeot out_unlock: 1221a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1222a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1223e3adcf8fSFrançois Tigeot drm_gem_object_unreference_unlocked(&new_bo->base); 1224e3adcf8fSFrançois Tigeot out_free: 1225158486a6SFrançois Tigeot kfree(params); 1226e3adcf8fSFrançois Tigeot 1227e3adcf8fSFrançois Tigeot return ret; 1228e3adcf8fSFrançois Tigeot } 1229e3adcf8fSFrançois Tigeot 1230e3adcf8fSFrançois Tigeot static void update_reg_attrs(struct intel_overlay *overlay, 1231e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 1232e3adcf8fSFrançois Tigeot { 1233e3440f96SFrançois Tigeot iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff), 1234e3440f96SFrançois Tigeot ®s->OCLRC0); 1235e3440f96SFrançois Tigeot iowrite32(overlay->saturation, ®s->OCLRC1); 1236e3adcf8fSFrançois Tigeot } 1237e3adcf8fSFrançois Tigeot 1238e3adcf8fSFrançois Tigeot static bool check_gamma_bounds(u32 gamma1, u32 gamma2) 1239e3adcf8fSFrançois Tigeot { 1240e3adcf8fSFrançois Tigeot int i; 1241e3adcf8fSFrançois Tigeot 1242e3adcf8fSFrançois Tigeot if (gamma1 & 0xff000000 || gamma2 & 0xff000000) 1243e3adcf8fSFrançois Tigeot return false; 1244e3adcf8fSFrançois Tigeot 1245e3adcf8fSFrançois Tigeot for (i = 0; i < 3; i++) { 1246e3adcf8fSFrançois Tigeot if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) 1247e3adcf8fSFrançois Tigeot return false; 1248e3adcf8fSFrançois Tigeot } 1249e3adcf8fSFrançois Tigeot 1250e3adcf8fSFrançois Tigeot return true; 1251e3adcf8fSFrançois Tigeot } 1252e3adcf8fSFrançois Tigeot 1253e3adcf8fSFrançois Tigeot static bool check_gamma5_errata(u32 gamma5) 1254e3adcf8fSFrançois Tigeot { 1255e3adcf8fSFrançois Tigeot int i; 1256e3adcf8fSFrançois Tigeot 1257e3adcf8fSFrançois Tigeot for (i = 0; i < 3; i++) { 1258e3adcf8fSFrançois Tigeot if (((gamma5 >> i*8) & 0xff) == 0x80) 1259e3adcf8fSFrançois Tigeot return false; 1260e3adcf8fSFrançois Tigeot } 1261e3adcf8fSFrançois Tigeot 1262e3adcf8fSFrançois Tigeot return true; 1263e3adcf8fSFrançois Tigeot } 1264e3adcf8fSFrançois Tigeot 1265e3adcf8fSFrançois Tigeot static int check_gamma(struct drm_intel_overlay_attrs *attrs) 1266e3adcf8fSFrançois Tigeot { 1267e3adcf8fSFrançois Tigeot if (!check_gamma_bounds(0, attrs->gamma0) || 1268e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || 1269e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || 1270e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || 1271e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || 1272e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || 1273e3adcf8fSFrançois Tigeot !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) 1274e3adcf8fSFrançois Tigeot return -EINVAL; 1275e3adcf8fSFrançois Tigeot 1276e3adcf8fSFrançois Tigeot if (!check_gamma5_errata(attrs->gamma5)) 1277e3adcf8fSFrançois Tigeot return -EINVAL; 1278e3adcf8fSFrançois Tigeot 1279e3adcf8fSFrançois Tigeot return 0; 1280e3adcf8fSFrançois Tigeot } 1281e3adcf8fSFrançois Tigeot 12821487f786SFrançois Tigeot int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, 1283e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 1284e3adcf8fSFrançois Tigeot { 1285e3adcf8fSFrançois Tigeot struct drm_intel_overlay_attrs *attrs = data; 1286*bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1287e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1288e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1289e3adcf8fSFrançois Tigeot int ret; 1290e3adcf8fSFrançois Tigeot 1291e3adcf8fSFrançois Tigeot overlay = dev_priv->overlay; 1292e3adcf8fSFrançois Tigeot if (!overlay) { 1293e3adcf8fSFrançois Tigeot DRM_DEBUG("userspace bug: no overlay\n"); 1294e3adcf8fSFrançois Tigeot return -ENODEV; 1295e3adcf8fSFrançois Tigeot } 1296e3adcf8fSFrançois Tigeot 1297a2fdbec6SFrançois Tigeot drm_modeset_lock_all(dev); 1298a2fdbec6SFrançois Tigeot mutex_lock(&dev->struct_mutex); 1299e3adcf8fSFrançois Tigeot 1300e3adcf8fSFrançois Tigeot ret = -EINVAL; 1301e3adcf8fSFrançois Tigeot if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { 1302e3adcf8fSFrançois Tigeot attrs->color_key = overlay->color_key; 1303e3adcf8fSFrançois Tigeot attrs->brightness = overlay->brightness; 1304e3adcf8fSFrançois Tigeot attrs->contrast = overlay->contrast; 1305e3adcf8fSFrançois Tigeot attrs->saturation = overlay->saturation; 1306e3adcf8fSFrançois Tigeot 13071487f786SFrançois Tigeot if (!IS_GEN2(dev_priv)) { 1308e3adcf8fSFrançois Tigeot attrs->gamma0 = I915_READ(OGAMC0); 1309e3adcf8fSFrançois Tigeot attrs->gamma1 = I915_READ(OGAMC1); 1310e3adcf8fSFrançois Tigeot attrs->gamma2 = I915_READ(OGAMC2); 1311e3adcf8fSFrançois Tigeot attrs->gamma3 = I915_READ(OGAMC3); 1312e3adcf8fSFrançois Tigeot attrs->gamma4 = I915_READ(OGAMC4); 1313e3adcf8fSFrançois Tigeot attrs->gamma5 = I915_READ(OGAMC5); 1314e3adcf8fSFrançois Tigeot } 1315e3adcf8fSFrançois Tigeot } else { 1316e3adcf8fSFrançois Tigeot if (attrs->brightness < -128 || attrs->brightness > 127) 1317e3adcf8fSFrançois Tigeot goto out_unlock; 1318e3adcf8fSFrançois Tigeot if (attrs->contrast > 255) 1319e3adcf8fSFrançois Tigeot goto out_unlock; 1320e3adcf8fSFrançois Tigeot if (attrs->saturation > 1023) 1321e3adcf8fSFrançois Tigeot goto out_unlock; 1322e3adcf8fSFrançois Tigeot 1323e3adcf8fSFrançois Tigeot overlay->color_key = attrs->color_key; 1324e3adcf8fSFrançois Tigeot overlay->brightness = attrs->brightness; 1325e3adcf8fSFrançois Tigeot overlay->contrast = attrs->contrast; 1326e3adcf8fSFrançois Tigeot overlay->saturation = attrs->saturation; 1327e3adcf8fSFrançois Tigeot 1328e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 1329e3adcf8fSFrançois Tigeot if (!regs) { 1330e3adcf8fSFrançois Tigeot ret = -ENOMEM; 1331e3adcf8fSFrançois Tigeot goto out_unlock; 1332e3adcf8fSFrançois Tigeot } 1333e3adcf8fSFrançois Tigeot 1334e3adcf8fSFrançois Tigeot update_reg_attrs(overlay, regs); 1335e3adcf8fSFrançois Tigeot 1336e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 1337e3adcf8fSFrançois Tigeot 1338e3adcf8fSFrançois Tigeot if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { 13391487f786SFrançois Tigeot if (IS_GEN2(dev_priv)) 1340e3adcf8fSFrançois Tigeot goto out_unlock; 1341e3adcf8fSFrançois Tigeot 1342e3adcf8fSFrançois Tigeot if (overlay->active) { 1343e3adcf8fSFrançois Tigeot ret = -EBUSY; 1344e3adcf8fSFrançois Tigeot goto out_unlock; 1345e3adcf8fSFrançois Tigeot } 1346e3adcf8fSFrançois Tigeot 1347e3adcf8fSFrançois Tigeot ret = check_gamma(attrs); 1348e3adcf8fSFrançois Tigeot if (ret) 1349e3adcf8fSFrançois Tigeot goto out_unlock; 1350e3adcf8fSFrançois Tigeot 1351e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC0, attrs->gamma0); 1352e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC1, attrs->gamma1); 1353e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC2, attrs->gamma2); 1354e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC3, attrs->gamma3); 1355e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC4, attrs->gamma4); 1356e3adcf8fSFrançois Tigeot I915_WRITE(OGAMC5, attrs->gamma5); 1357e3adcf8fSFrançois Tigeot } 1358e3adcf8fSFrançois Tigeot } 135919c468b4SFrançois Tigeot overlay->color_key_enabled = (attrs->flags & I915_OVERLAY_DISABLE_DEST_COLORKEY) == 0; 1360e3adcf8fSFrançois Tigeot 1361e3adcf8fSFrançois Tigeot ret = 0; 1362e3adcf8fSFrançois Tigeot out_unlock: 1363a2fdbec6SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 1364a2fdbec6SFrançois Tigeot drm_modeset_unlock_all(dev); 1365e3adcf8fSFrançois Tigeot 1366e3adcf8fSFrançois Tigeot return ret; 1367e3adcf8fSFrançois Tigeot } 1368e3adcf8fSFrançois Tigeot 13691487f786SFrançois Tigeot void intel_setup_overlay(struct drm_i915_private *dev_priv) 1370e3adcf8fSFrançois Tigeot { 1371e3adcf8fSFrançois Tigeot struct intel_overlay *overlay; 1372e3adcf8fSFrançois Tigeot struct drm_i915_gem_object *reg_bo; 1373e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1374e3adcf8fSFrançois Tigeot int ret; 1375e3adcf8fSFrançois Tigeot 13761487f786SFrançois Tigeot if (!HAS_OVERLAY(dev_priv)) 1377e3adcf8fSFrançois Tigeot return; 1378e3adcf8fSFrançois Tigeot 13799edbd4a0SFrançois Tigeot overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); 1380e3440f96SFrançois Tigeot if (!overlay) 1381e3440f96SFrançois Tigeot return; 1382e3440f96SFrançois Tigeot 1383303bf270SFrançois Tigeot mutex_lock(&dev_priv->drm.struct_mutex); 1384e3440f96SFrançois Tigeot if (WARN_ON(dev_priv->overlay)) 1385e3adcf8fSFrançois Tigeot goto out_free; 1386e3440f96SFrançois Tigeot 13871487f786SFrançois Tigeot overlay->i915 = dev_priv; 1388e3adcf8fSFrançois Tigeot 13899edbd4a0SFrançois Tigeot reg_bo = NULL; 13901487f786SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(dev_priv)) 1391303bf270SFrançois Tigeot reg_bo = i915_gem_object_create_stolen(&dev_priv->drm, 1392303bf270SFrançois Tigeot PAGE_SIZE); 13939edbd4a0SFrançois Tigeot if (reg_bo == NULL) 1394303bf270SFrançois Tigeot reg_bo = i915_gem_object_create(&dev_priv->drm, PAGE_SIZE); 13951487f786SFrançois Tigeot if (IS_ERR(reg_bo)) 1396e3adcf8fSFrançois Tigeot goto out_free; 1397e3adcf8fSFrançois Tigeot overlay->reg_bo = reg_bo; 1398e3adcf8fSFrançois Tigeot 13991487f786SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) { 1400ba55f2f5SFrançois Tigeot ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE); 1401e3adcf8fSFrançois Tigeot if (ret) { 1402e3adcf8fSFrançois Tigeot DRM_ERROR("failed to attach phys overlay regs\n"); 1403e3adcf8fSFrançois Tigeot goto out_free_bo; 1404e3adcf8fSFrançois Tigeot } 1405ba55f2f5SFrançois Tigeot overlay->flip_addr = reg_bo->phys_handle->busaddr; 1406e3adcf8fSFrançois Tigeot } else { 1407ba55f2f5SFrançois Tigeot ret = i915_gem_obj_ggtt_pin(reg_bo, PAGE_SIZE, PIN_MAPPABLE); 1408e3adcf8fSFrançois Tigeot if (ret) { 1409e3adcf8fSFrançois Tigeot DRM_ERROR("failed to pin overlay register bo\n"); 1410e3adcf8fSFrançois Tigeot goto out_free_bo; 1411e3adcf8fSFrançois Tigeot } 14129edbd4a0SFrançois Tigeot overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo); 1413e3adcf8fSFrançois Tigeot 1414e3adcf8fSFrançois Tigeot ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); 1415e3adcf8fSFrançois Tigeot if (ret) { 1416e3adcf8fSFrançois Tigeot DRM_ERROR("failed to move overlay register bo into the GTT\n"); 1417e3adcf8fSFrançois Tigeot goto out_unpin_bo; 1418e3adcf8fSFrançois Tigeot } 1419e3adcf8fSFrançois Tigeot } 1420e3adcf8fSFrançois Tigeot 1421e3adcf8fSFrançois Tigeot /* init all values */ 1422e3adcf8fSFrançois Tigeot overlay->color_key = 0x0101fe; 142319c468b4SFrançois Tigeot overlay->color_key_enabled = true; 1424e3adcf8fSFrançois Tigeot overlay->brightness = -19; 1425e3adcf8fSFrançois Tigeot overlay->contrast = 75; 1426e3adcf8fSFrançois Tigeot overlay->saturation = 146; 1427e3adcf8fSFrançois Tigeot 1428e3adcf8fSFrançois Tigeot regs = intel_overlay_map_regs(overlay); 1429e3adcf8fSFrançois Tigeot if (!regs) 1430e3adcf8fSFrançois Tigeot goto out_unpin_bo; 1431e3adcf8fSFrançois Tigeot 1432e3440f96SFrançois Tigeot memset_io(regs, 0, sizeof(struct overlay_registers)); 1433e3adcf8fSFrançois Tigeot update_polyphase_filter(regs); 1434e3adcf8fSFrançois Tigeot update_reg_attrs(overlay, regs); 1435e3adcf8fSFrançois Tigeot 1436e3adcf8fSFrançois Tigeot intel_overlay_unmap_regs(overlay, regs); 1437e3adcf8fSFrançois Tigeot 1438e3adcf8fSFrançois Tigeot dev_priv->overlay = overlay; 1439303bf270SFrançois Tigeot mutex_unlock(&dev_priv->drm.struct_mutex); 1440e3440f96SFrançois Tigeot DRM_INFO("initialized overlay support\n"); 1441e3adcf8fSFrançois Tigeot return; 1442e3adcf8fSFrançois Tigeot 1443e3adcf8fSFrançois Tigeot out_unpin_bo: 14441487f786SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(dev_priv)) 1445ba55f2f5SFrançois Tigeot i915_gem_object_ggtt_unpin(reg_bo); 1446e3adcf8fSFrançois Tigeot out_free_bo: 1447e3adcf8fSFrançois Tigeot drm_gem_object_unreference(®_bo->base); 1448e3adcf8fSFrançois Tigeot out_free: 1449303bf270SFrançois Tigeot mutex_unlock(&dev_priv->drm.struct_mutex); 1450158486a6SFrançois Tigeot kfree(overlay); 1451e3adcf8fSFrançois Tigeot return; 1452e3adcf8fSFrançois Tigeot } 1453e3adcf8fSFrançois Tigeot 14541487f786SFrançois Tigeot void intel_cleanup_overlay(struct drm_i915_private *dev_priv) 1455e3adcf8fSFrançois Tigeot { 1456e3adcf8fSFrançois Tigeot if (!dev_priv->overlay) 1457e3adcf8fSFrançois Tigeot return; 1458e3adcf8fSFrançois Tigeot 1459e3adcf8fSFrançois Tigeot /* The bo's should be free'd by the generic code already. 1460e3adcf8fSFrançois Tigeot * Furthermore modesetting teardown happens beforehand so the 1461e3adcf8fSFrançois Tigeot * hardware should be off already */ 146219c468b4SFrançois Tigeot WARN_ON(dev_priv->overlay->active); 1463e3adcf8fSFrançois Tigeot 1464e3adcf8fSFrançois Tigeot drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base); 1465158486a6SFrançois Tigeot kfree(dev_priv->overlay); 1466e3adcf8fSFrançois Tigeot } 1467e3adcf8fSFrançois Tigeot 1468e3adcf8fSFrançois Tigeot struct intel_overlay_error_state { 1469e3adcf8fSFrançois Tigeot struct overlay_registers regs; 1470e3adcf8fSFrançois Tigeot unsigned long base; 1471e3adcf8fSFrançois Tigeot u32 dovsta; 1472e3adcf8fSFrançois Tigeot u32 isr; 1473e3adcf8fSFrançois Tigeot }; 1474e3adcf8fSFrançois Tigeot 1475e3440f96SFrançois Tigeot static struct overlay_registers __iomem * 1476e3440f96SFrançois Tigeot intel_overlay_map_regs_atomic(struct intel_overlay *overlay) 1477e3440f96SFrançois Tigeot { 14781487f786SFrançois Tigeot struct drm_i915_private *dev_priv = overlay->i915; 1479e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs; 1480e3440f96SFrançois Tigeot 14811487f786SFrançois Tigeot if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) 1482e3440f96SFrançois Tigeot /* Cast to make sparse happy, but it's wc memory anyway, so 1483e3440f96SFrançois Tigeot * equivalent to the wc io mapping on X86. */ 1484e3440f96SFrançois Tigeot regs = (struct overlay_registers __iomem *) 14852c9916cdSFrançois Tigeot overlay->reg_bo->phys_handle->vaddr; 1486e3440f96SFrançois Tigeot else 14871487f786SFrançois Tigeot regs = io_mapping_map_atomic_wc(dev_priv->ggtt.mappable, 14881487f786SFrançois Tigeot overlay->flip_addr); 1489e3440f96SFrançois Tigeot 1490e3440f96SFrançois Tigeot return regs; 1491e3440f96SFrançois Tigeot } 1492e3440f96SFrançois Tigeot 1493e3440f96SFrançois Tigeot static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, 1494e3440f96SFrançois Tigeot struct overlay_registers __iomem *regs) 1495e3440f96SFrançois Tigeot { 14961487f786SFrançois Tigeot if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915)) 1497e3440f96SFrançois Tigeot io_mapping_unmap_atomic(regs); 1498e3440f96SFrançois Tigeot } 1499e3440f96SFrançois Tigeot 1500e3adcf8fSFrançois Tigeot struct intel_overlay_error_state * 15011487f786SFrançois Tigeot intel_overlay_capture_error_state(struct drm_i915_private *dev_priv) 1502e3adcf8fSFrançois Tigeot { 1503e3adcf8fSFrançois Tigeot struct intel_overlay *overlay = dev_priv->overlay; 1504e3adcf8fSFrançois Tigeot struct intel_overlay_error_state *error; 1505e3adcf8fSFrançois Tigeot struct overlay_registers __iomem *regs; 1506e3adcf8fSFrançois Tigeot 1507e3adcf8fSFrançois Tigeot if (!overlay || !overlay->active) 1508e3adcf8fSFrançois Tigeot return NULL; 1509e3adcf8fSFrançois Tigeot 1510*bf017597SFrançois Tigeot error = kmalloc(sizeof(*error), M_DRM, GFP_ATOMIC); 1511e3adcf8fSFrançois Tigeot if (error == NULL) 1512e3adcf8fSFrançois Tigeot return NULL; 1513e3adcf8fSFrançois Tigeot 1514e3adcf8fSFrançois Tigeot error->dovsta = I915_READ(DOVSTA); 1515e3adcf8fSFrançois Tigeot error->isr = I915_READ(ISR); 15161487f786SFrançois Tigeot error->base = overlay->flip_addr; 1517e3adcf8fSFrançois Tigeot 1518e3440f96SFrançois Tigeot regs = intel_overlay_map_regs_atomic(overlay); 1519e3adcf8fSFrançois Tigeot if (!regs) 1520e3adcf8fSFrançois Tigeot goto err; 1521e3adcf8fSFrançois Tigeot 1522e3440f96SFrançois Tigeot memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); 1523e3440f96SFrançois Tigeot intel_overlay_unmap_regs_atomic(overlay, regs); 1524e3adcf8fSFrançois Tigeot 1525e3440f96SFrançois Tigeot return error; 1526e3adcf8fSFrançois Tigeot 1527e3adcf8fSFrançois Tigeot err: 1528158486a6SFrançois Tigeot kfree(error); 1529e3440f96SFrançois Tigeot return NULL; 1530e3adcf8fSFrançois Tigeot } 1531e3adcf8fSFrançois Tigeot 1532e3adcf8fSFrançois Tigeot void 15335d0b1887SFrançois Tigeot intel_overlay_print_error_state(struct drm_i915_error_state_buf *m, 15345d0b1887SFrançois Tigeot struct intel_overlay_error_state *error) 1535e3adcf8fSFrançois Tigeot { 15365d0b1887SFrançois Tigeot i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", 1537e3adcf8fSFrançois Tigeot error->dovsta, error->isr); 15385d0b1887SFrançois Tigeot i915_error_printf(m, " Register file at 0x%08lx:\n", 1539e3adcf8fSFrançois Tigeot error->base); 1540e3adcf8fSFrançois Tigeot 15415d0b1887SFrançois Tigeot #define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x) 1542e3adcf8fSFrançois Tigeot P(OBUF_0Y); 1543e3adcf8fSFrançois Tigeot P(OBUF_1Y); 1544e3adcf8fSFrançois Tigeot P(OBUF_0U); 1545e3adcf8fSFrançois Tigeot P(OBUF_0V); 1546e3adcf8fSFrançois Tigeot P(OBUF_1U); 1547e3adcf8fSFrançois Tigeot P(OBUF_1V); 1548e3adcf8fSFrançois Tigeot P(OSTRIDE); 1549e3adcf8fSFrançois Tigeot P(YRGB_VPH); 1550e3adcf8fSFrançois Tigeot P(UV_VPH); 1551e3adcf8fSFrançois Tigeot P(HORZ_PH); 1552e3adcf8fSFrançois Tigeot P(INIT_PHS); 1553e3adcf8fSFrançois Tigeot P(DWINPOS); 1554e3adcf8fSFrançois Tigeot P(DWINSZ); 1555e3adcf8fSFrançois Tigeot P(SWIDTH); 1556e3adcf8fSFrançois Tigeot P(SWIDTHSW); 1557e3adcf8fSFrançois Tigeot P(SHEIGHT); 1558e3adcf8fSFrançois Tigeot P(YRGBSCALE); 1559e3adcf8fSFrançois Tigeot P(UVSCALE); 1560e3adcf8fSFrançois Tigeot P(OCLRC0); 1561e3adcf8fSFrançois Tigeot P(OCLRC1); 1562e3adcf8fSFrançois Tigeot P(DCLRKV); 1563e3adcf8fSFrançois Tigeot P(DCLRKM); 1564e3adcf8fSFrançois Tigeot P(SCLRKVH); 1565e3adcf8fSFrançois Tigeot P(SCLRKVL); 1566e3adcf8fSFrançois Tigeot P(SCLRKEN); 1567e3adcf8fSFrançois Tigeot P(OCONFIG); 1568e3adcf8fSFrançois Tigeot P(OCMD); 1569e3adcf8fSFrançois Tigeot P(OSTART_0Y); 1570e3adcf8fSFrançois Tigeot P(OSTART_1Y); 1571e3adcf8fSFrançois Tigeot P(OSTART_0U); 1572e3adcf8fSFrançois Tigeot P(OSTART_0V); 1573e3adcf8fSFrançois Tigeot P(OSTART_1U); 1574e3adcf8fSFrançois Tigeot P(OSTART_1V); 1575e3adcf8fSFrançois Tigeot P(OTILEOFF_0Y); 1576e3adcf8fSFrançois Tigeot P(OTILEOFF_1Y); 1577e3adcf8fSFrançois Tigeot P(OTILEOFF_0U); 1578e3adcf8fSFrançois Tigeot P(OTILEOFF_0V); 1579e3adcf8fSFrançois Tigeot P(OTILEOFF_1U); 1580e3adcf8fSFrançois Tigeot P(OTILEOFF_1V); 1581e3adcf8fSFrançois Tigeot P(FASTHSCALE); 1582e3adcf8fSFrançois Tigeot P(UVSCALEV); 1583e3adcf8fSFrançois Tigeot #undef P 1584e3adcf8fSFrançois Tigeot } 1585