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