1235783Skib/* 2235783Skib * Copyright �� 2009 3235783Skib * 4235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 5235783Skib * copy of this software and associated documentation files (the "Software"), 6235783Skib * to deal in the Software without restriction, including without limitation 7235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8235783Skib * and/or sell copies of the Software, and to permit persons to whom the 9235783Skib * Software is furnished to do so, subject to the following conditions: 10235783Skib * 11235783Skib * The above copyright notice and this permission notice (including the next 12235783Skib * paragraph) shall be included in all copies or substantial portions of the 13235783Skib * Software. 14235783Skib * 15235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20235783Skib * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21235783Skib * SOFTWARE. 22235783Skib * 23235783Skib * Authors: 24235783Skib * Daniel Vetter <daniel@ffwll.ch> 25235783Skib * 26235783Skib * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c 27235783Skib */ 28235783Skib 29235783Skib#include <sys/cdefs.h> 30235783Skib__FBSDID("$FreeBSD$"); 31235783Skib 32235783Skib#include <dev/drm2/drmP.h> 33235783Skib#include <dev/drm2/drm.h> 34235783Skib#include <dev/drm2/i915/i915_drm.h> 35235783Skib#include <dev/drm2/i915/i915_drv.h> 36235783Skib#include <dev/drm2/i915/i915_reg.h> 37235783Skib#include <dev/drm2/i915/intel_drv.h> 38235783Skib 39235783Skib/* Limits for overlay size. According to intel doc, the real limits are: 40235783Skib * Y width: 4095, UV width (planar): 2047, Y height: 2047, 41235783Skib * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use 42235783Skib * the mininum of both. */ 43235783Skib#define IMAGE_MAX_WIDTH 2048 44235783Skib#define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */ 45235783Skib/* on 830 and 845 these large limits result in the card hanging */ 46235783Skib#define IMAGE_MAX_WIDTH_LEGACY 1024 47235783Skib#define IMAGE_MAX_HEIGHT_LEGACY 1088 48235783Skib 49235783Skib/* overlay register definitions */ 50235783Skib/* OCMD register */ 51235783Skib#define OCMD_TILED_SURFACE (0x1<<19) 52235783Skib#define OCMD_MIRROR_MASK (0x3<<17) 53235783Skib#define OCMD_MIRROR_MODE (0x3<<17) 54235783Skib#define OCMD_MIRROR_HORIZONTAL (0x1<<17) 55235783Skib#define OCMD_MIRROR_VERTICAL (0x2<<17) 56235783Skib#define OCMD_MIRROR_BOTH (0x3<<17) 57235783Skib#define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */ 58235783Skib#define OCMD_UV_SWAP (0x1<<14) /* YVYU */ 59235783Skib#define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */ 60235783Skib#define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */ 61235783Skib#define OCMD_SOURCE_FORMAT_MASK (0xf<<10) 62235783Skib#define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */ 63235783Skib#define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */ 64235783Skib#define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */ 65235783Skib#define OCMD_YUV_422_PACKED (0x8<<10) 66235783Skib#define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */ 67235783Skib#define OCMD_YUV_420_PLANAR (0xc<<10) 68235783Skib#define OCMD_YUV_422_PLANAR (0xd<<10) 69235783Skib#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */ 70235783Skib#define OCMD_TVSYNCFLIP_PARITY (0x1<<9) 71235783Skib#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7) 72235783Skib#define OCMD_BUF_TYPE_MASK (0x1<<5) 73235783Skib#define OCMD_BUF_TYPE_FRAME (0x0<<5) 74235783Skib#define OCMD_BUF_TYPE_FIELD (0x1<<5) 75235783Skib#define OCMD_TEST_MODE (0x1<<4) 76235783Skib#define OCMD_BUFFER_SELECT (0x3<<2) 77235783Skib#define OCMD_BUFFER0 (0x0<<2) 78235783Skib#define OCMD_BUFFER1 (0x1<<2) 79235783Skib#define OCMD_FIELD_SELECT (0x1<<2) 80235783Skib#define OCMD_FIELD0 (0x0<<1) 81235783Skib#define OCMD_FIELD1 (0x1<<1) 82235783Skib#define OCMD_ENABLE (0x1<<0) 83235783Skib 84235783Skib/* OCONFIG register */ 85235783Skib#define OCONF_PIPE_MASK (0x1<<18) 86235783Skib#define OCONF_PIPE_A (0x0<<18) 87235783Skib#define OCONF_PIPE_B (0x1<<18) 88235783Skib#define OCONF_GAMMA2_ENABLE (0x1<<16) 89235783Skib#define OCONF_CSC_MODE_BT601 (0x0<<5) 90235783Skib#define OCONF_CSC_MODE_BT709 (0x1<<5) 91235783Skib#define OCONF_CSC_BYPASS (0x1<<4) 92235783Skib#define OCONF_CC_OUT_8BIT (0x1<<3) 93235783Skib#define OCONF_TEST_MODE (0x1<<2) 94235783Skib#define OCONF_THREE_LINE_BUFFER (0x1<<0) 95235783Skib#define OCONF_TWO_LINE_BUFFER (0x0<<0) 96235783Skib 97235783Skib/* DCLRKM (dst-key) register */ 98235783Skib#define DST_KEY_ENABLE (0x1<<31) 99235783Skib#define CLK_RGB24_MASK 0x0 100235783Skib#define CLK_RGB16_MASK 0x070307 101235783Skib#define CLK_RGB15_MASK 0x070707 102235783Skib#define CLK_RGB8I_MASK 0xffffff 103235783Skib 104235783Skib#define RGB16_TO_COLORKEY(c) \ 105235783Skib (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) 106235783Skib#define RGB15_TO_COLORKEY(c) \ 107235783Skib (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3)) 108235783Skib 109235783Skib/* overlay flip addr flag */ 110235783Skib#define OFC_UPDATE 0x1 111235783Skib 112235783Skib/* polyphase filter coefficients */ 113235783Skib#define N_HORIZ_Y_TAPS 5 114235783Skib#define N_VERT_Y_TAPS 3 115235783Skib#define N_HORIZ_UV_TAPS 3 116235783Skib#define N_VERT_UV_TAPS 3 117235783Skib#define N_PHASES 17 118235783Skib#define MAX_TAPS 5 119235783Skib 120235783Skib/* memory bufferd overlay registers */ 121235783Skibstruct overlay_registers { 122235783Skib u32 OBUF_0Y; 123235783Skib u32 OBUF_1Y; 124235783Skib u32 OBUF_0U; 125235783Skib u32 OBUF_0V; 126235783Skib u32 OBUF_1U; 127235783Skib u32 OBUF_1V; 128235783Skib u32 OSTRIDE; 129235783Skib u32 YRGB_VPH; 130235783Skib u32 UV_VPH; 131235783Skib u32 HORZ_PH; 132235783Skib u32 INIT_PHS; 133235783Skib u32 DWINPOS; 134235783Skib u32 DWINSZ; 135235783Skib u32 SWIDTH; 136235783Skib u32 SWIDTHSW; 137235783Skib u32 SHEIGHT; 138235783Skib u32 YRGBSCALE; 139235783Skib u32 UVSCALE; 140235783Skib u32 OCLRC0; 141235783Skib u32 OCLRC1; 142235783Skib u32 DCLRKV; 143235783Skib u32 DCLRKM; 144235783Skib u32 SCLRKVH; 145235783Skib u32 SCLRKVL; 146235783Skib u32 SCLRKEN; 147235783Skib u32 OCONFIG; 148235783Skib u32 OCMD; 149235783Skib u32 RESERVED1; /* 0x6C */ 150235783Skib u32 OSTART_0Y; 151235783Skib u32 OSTART_1Y; 152235783Skib u32 OSTART_0U; 153235783Skib u32 OSTART_0V; 154235783Skib u32 OSTART_1U; 155235783Skib u32 OSTART_1V; 156235783Skib u32 OTILEOFF_0Y; 157235783Skib u32 OTILEOFF_1Y; 158235783Skib u32 OTILEOFF_0U; 159235783Skib u32 OTILEOFF_0V; 160235783Skib u32 OTILEOFF_1U; 161235783Skib u32 OTILEOFF_1V; 162235783Skib u32 FASTHSCALE; /* 0xA0 */ 163235783Skib u32 UVSCALEV; /* 0xA4 */ 164235783Skib u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */ 165235783Skib u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */ 166235783Skib u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES]; 167235783Skib u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */ 168235783Skib u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES]; 169235783Skib u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */ 170235783Skib u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES]; 171235783Skib u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */ 172235783Skib u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; 173235783Skib}; 174235783Skib 175235783Skibstruct intel_overlay { 176235783Skib struct drm_device *dev; 177235783Skib struct intel_crtc *crtc; 178235783Skib struct drm_i915_gem_object *vid_bo; 179235783Skib struct drm_i915_gem_object *old_vid_bo; 180235783Skib int active; 181235783Skib int pfit_active; 182235783Skib u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ 183235783Skib u32 color_key; 184235783Skib u32 brightness, contrast, saturation; 185235783Skib u32 old_xscale, old_yscale; 186235783Skib /* register access */ 187235783Skib u32 flip_addr; 188235783Skib struct drm_i915_gem_object *reg_bo; 189235783Skib /* flip handling */ 190235783Skib uint32_t last_flip_req; 191235783Skib void (*flip_tail)(struct intel_overlay *); 192235783Skib}; 193235783Skib 194235783Skibstatic struct overlay_registers * 195235783Skibintel_overlay_map_regs(struct intel_overlay *overlay) 196235783Skib{ 197235783Skib struct overlay_registers *regs; 198235783Skib 199235783Skib if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) { 200235783Skib regs = overlay->reg_bo->phys_obj->handle->vaddr; 201235783Skib } else { 202235783Skib regs = pmap_mapdev_attr(overlay->dev->agp->base + 203235783Skib overlay->reg_bo->gtt_offset, PAGE_SIZE, 204235783Skib PAT_WRITE_COMBINING); 205235783Skib } 206235783Skib return (regs); 207235783Skib} 208235783Skib 209235783Skibstatic void intel_overlay_unmap_regs(struct intel_overlay *overlay, 210235783Skib struct overlay_registers *regs) 211235783Skib{ 212235783Skib if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 213235783Skib pmap_unmapdev((vm_offset_t)regs, PAGE_SIZE); 214235783Skib} 215235783Skib 216235783Skibstatic int intel_overlay_do_wait_request(struct intel_overlay *overlay, 217235783Skib struct drm_i915_gem_request *request, 218235783Skib void (*tail)(struct intel_overlay *)) 219235783Skib{ 220235783Skib struct drm_device *dev = overlay->dev; 221235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 222235783Skib int ret; 223235783Skib 224235783Skib KASSERT(!overlay->last_flip_req, ("Overlay already has flip req")); 225235783Skib ret = i915_add_request(LP_RING(dev_priv), NULL, request); 226235783Skib if (ret) { 227235783Skib free(request, DRM_I915_GEM); 228235783Skib return ret; 229235783Skib } 230235783Skib overlay->last_flip_req = request->seqno; 231235783Skib overlay->flip_tail = tail; 232235783Skib ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req, 233235783Skib true); 234235783Skib if (ret) 235235783Skib return ret; 236235783Skib 237235783Skib overlay->last_flip_req = 0; 238235783Skib return 0; 239235783Skib} 240235783Skib 241235783Skib/* Workaround for i830 bug where pipe a must be enable to change control regs */ 242235783Skibstatic int 243235783Skibi830_activate_pipe_a(struct drm_device *dev) 244235783Skib{ 245235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 246235783Skib struct intel_crtc *crtc; 247235783Skib struct drm_crtc_helper_funcs *crtc_funcs; 248235783Skib struct drm_display_mode vesa_640x480 = { 249235783Skib DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 250235783Skib 752, 800, 0, 480, 489, 492, 525, 0, 251235783Skib DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) 252235783Skib }, *mode; 253235783Skib 254235783Skib crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]); 255235783Skib if (crtc->dpms_mode == DRM_MODE_DPMS_ON) 256235783Skib return 0; 257235783Skib 258235783Skib /* most i8xx have pipe a forced on, so don't trust dpms mode */ 259235783Skib if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE) 260235783Skib return 0; 261235783Skib 262235783Skib crtc_funcs = crtc->base.helper_private; 263235783Skib if (crtc_funcs->dpms == NULL) 264235783Skib return 0; 265235783Skib 266235783Skib DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); 267235783Skib 268235783Skib mode = drm_mode_duplicate(dev, &vesa_640x480); 269235783Skib drm_mode_set_crtcinfo(mode, 0); 270235783Skib if (!drm_crtc_helper_set_mode(&crtc->base, mode, 271235783Skib crtc->base.x, crtc->base.y, 272235783Skib crtc->base.fb)) 273235783Skib return 0; 274235783Skib 275235783Skib crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON); 276235783Skib return 1; 277235783Skib} 278235783Skib 279235783Skibstatic void 280235783Skibi830_deactivate_pipe_a(struct drm_device *dev) 281235783Skib{ 282235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 283235783Skib struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; 284235783Skib struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 285235783Skib 286235783Skib crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); 287235783Skib} 288235783Skib 289235783Skib/* overlay needs to be disable in OCMD reg */ 290235783Skibstatic int intel_overlay_on(struct intel_overlay *overlay) 291235783Skib{ 292235783Skib struct drm_device *dev = overlay->dev; 293235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 294235783Skib struct drm_i915_gem_request *request; 295235783Skib int pipe_a_quirk = 0; 296235783Skib int ret; 297235783Skib 298235783Skib KASSERT(!overlay->active, ("Overlay is active")); 299235783Skib overlay->active = 1; 300235783Skib 301235783Skib if (IS_I830(dev)) { 302235783Skib pipe_a_quirk = i830_activate_pipe_a(dev); 303235783Skib if (pipe_a_quirk < 0) 304235783Skib return pipe_a_quirk; 305235783Skib } 306235783Skib 307235783Skib request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); 308235783Skib 309235783Skib ret = BEGIN_LP_RING(4); 310235783Skib if (ret) { 311235783Skib free(request, DRM_I915_GEM); 312235783Skib goto out; 313235783Skib } 314235783Skib 315235783Skib OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); 316235783Skib OUT_RING(overlay->flip_addr | OFC_UPDATE); 317235783Skib OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 318235783Skib OUT_RING(MI_NOOP); 319235783Skib ADVANCE_LP_RING(); 320235783Skib 321235783Skib ret = intel_overlay_do_wait_request(overlay, request, NULL); 322235783Skibout: 323235783Skib if (pipe_a_quirk) 324235783Skib i830_deactivate_pipe_a(dev); 325235783Skib 326235783Skib return ret; 327235783Skib} 328235783Skib 329235783Skib/* overlay needs to be enabled in OCMD reg */ 330235783Skibstatic int intel_overlay_continue(struct intel_overlay *overlay, 331235783Skib bool load_polyphase_filter) 332235783Skib{ 333235783Skib struct drm_device *dev = overlay->dev; 334235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 335235783Skib struct drm_i915_gem_request *request; 336235783Skib u32 flip_addr = overlay->flip_addr; 337235783Skib u32 tmp; 338235783Skib int ret; 339235783Skib 340235783Skib KASSERT(overlay->active, ("Overlay not active")); 341235783Skib 342235783Skib request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); 343235783Skib 344235783Skib if (load_polyphase_filter) 345235783Skib flip_addr |= OFC_UPDATE; 346235783Skib 347235783Skib /* check for underruns */ 348235783Skib tmp = I915_READ(DOVSTA); 349235783Skib if (tmp & (1 << 17)) 350235783Skib DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); 351235783Skib 352235783Skib ret = BEGIN_LP_RING(2); 353235783Skib if (ret) { 354235783Skib free(request, DRM_I915_GEM); 355235783Skib return ret; 356235783Skib } 357235783Skib OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 358235783Skib OUT_RING(flip_addr); 359235783Skib ADVANCE_LP_RING(); 360235783Skib 361235783Skib ret = i915_add_request(LP_RING(dev_priv), NULL, request); 362235783Skib if (ret) { 363235783Skib free(request, DRM_I915_GEM); 364235783Skib return ret; 365235783Skib } 366235783Skib 367235783Skib overlay->last_flip_req = request->seqno; 368235783Skib return 0; 369235783Skib} 370235783Skib 371235783Skibstatic void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) 372235783Skib{ 373235783Skib struct drm_i915_gem_object *obj = overlay->old_vid_bo; 374235783Skib 375235783Skib i915_gem_object_unpin(obj); 376235783Skib drm_gem_object_unreference(&obj->base); 377235783Skib 378235783Skib overlay->old_vid_bo = NULL; 379235783Skib} 380235783Skib 381235783Skibstatic void intel_overlay_off_tail(struct intel_overlay *overlay) 382235783Skib{ 383235783Skib struct drm_i915_gem_object *obj = overlay->vid_bo; 384235783Skib 385235783Skib /* never have the overlay hw on without showing a frame */ 386235783Skib KASSERT(overlay->vid_bo != NULL, ("No vid_bo")); 387235783Skib 388235783Skib i915_gem_object_unpin(obj); 389235783Skib drm_gem_object_unreference(&obj->base); 390235783Skib overlay->vid_bo = NULL; 391235783Skib 392235783Skib overlay->crtc->overlay = NULL; 393235783Skib overlay->crtc = NULL; 394235783Skib overlay->active = 0; 395235783Skib} 396235783Skib 397235783Skib/* overlay needs to be disabled in OCMD reg */ 398235783Skibstatic int intel_overlay_off(struct intel_overlay *overlay) 399235783Skib{ 400235783Skib struct drm_device *dev = overlay->dev; 401235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 402235783Skib u32 flip_addr = overlay->flip_addr; 403235783Skib struct drm_i915_gem_request *request; 404235783Skib int ret; 405235783Skib 406235783Skib KASSERT(overlay->active, ("Overlay is not active")); 407235783Skib 408235783Skib request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); 409235783Skib 410235783Skib /* According to intel docs the overlay hw may hang (when switching 411235783Skib * off) without loading the filter coeffs. It is however unclear whether 412235783Skib * this applies to the disabling of the overlay or to the switching off 413235783Skib * of the hw. Do it in both cases */ 414235783Skib flip_addr |= OFC_UPDATE; 415235783Skib 416235783Skib ret = BEGIN_LP_RING(6); 417235783Skib if (ret) { 418235783Skib free(request, DRM_I915_GEM); 419235783Skib return ret; 420235783Skib } 421235783Skib /* wait for overlay to go idle */ 422235783Skib OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); 423235783Skib OUT_RING(flip_addr); 424235783Skib OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 425235783Skib /* turn overlay off */ 426235783Skib OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); 427235783Skib OUT_RING(flip_addr); 428235783Skib OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 429235783Skib ADVANCE_LP_RING(); 430235783Skib 431235783Skib return intel_overlay_do_wait_request(overlay, request, 432235783Skib intel_overlay_off_tail); 433235783Skib} 434235783Skib 435235783Skib/* recover from an interruption due to a signal 436235783Skib * We have to be careful not to repeat work forever an make forward progess. */ 437235783Skibstatic int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) 438235783Skib{ 439235783Skib struct drm_device *dev = overlay->dev; 440235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 441235783Skib int ret; 442235783Skib 443235783Skib if (overlay->last_flip_req == 0) 444235783Skib return 0; 445235783Skib 446235783Skib ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req, 447235783Skib true); 448235783Skib if (ret) 449235783Skib return ret; 450235783Skib 451235783Skib if (overlay->flip_tail) 452235783Skib overlay->flip_tail(overlay); 453235783Skib 454235783Skib overlay->last_flip_req = 0; 455235783Skib return 0; 456235783Skib} 457235783Skib 458235783Skib/* Wait for pending overlay flip and release old frame. 459235783Skib * Needs to be called before the overlay register are changed 460235783Skib * via intel_overlay_(un)map_regs 461235783Skib */ 462235783Skibstatic int intel_overlay_release_old_vid(struct intel_overlay *overlay) 463235783Skib{ 464235783Skib struct drm_device *dev = overlay->dev; 465235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 466235783Skib int ret; 467235783Skib 468235783Skib /* Only wait if there is actually an old frame to release to 469235783Skib * guarantee forward progress. 470235783Skib */ 471235783Skib if (!overlay->old_vid_bo) 472235783Skib return 0; 473235783Skib 474235783Skib if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { 475235783Skib struct drm_i915_gem_request *request; 476235783Skib 477235783Skib /* synchronous slowpath */ 478235783Skib request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); 479235783Skib 480235783Skib ret = BEGIN_LP_RING(2); 481235783Skib if (ret) { 482235783Skib free(request, DRM_I915_GEM); 483235783Skib return ret; 484235783Skib } 485235783Skib 486235783Skib OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 487235783Skib OUT_RING(MI_NOOP); 488235783Skib ADVANCE_LP_RING(); 489235783Skib 490235783Skib ret = intel_overlay_do_wait_request(overlay, request, 491235783Skib intel_overlay_release_old_vid_tail); 492235783Skib if (ret) 493235783Skib return ret; 494235783Skib } 495235783Skib 496235783Skib intel_overlay_release_old_vid_tail(overlay); 497235783Skib return 0; 498235783Skib} 499235783Skib 500235783Skibstruct put_image_params { 501235783Skib int format; 502235783Skib short dst_x; 503235783Skib short dst_y; 504235783Skib short dst_w; 505235783Skib short dst_h; 506235783Skib short src_w; 507235783Skib short src_scan_h; 508235783Skib short src_scan_w; 509235783Skib short src_h; 510235783Skib short stride_Y; 511235783Skib short stride_UV; 512235783Skib int offset_Y; 513235783Skib int offset_U; 514235783Skib int offset_V; 515235783Skib}; 516235783Skib 517235783Skibstatic int packed_depth_bytes(u32 format) 518235783Skib{ 519235783Skib switch (format & I915_OVERLAY_DEPTH_MASK) { 520235783Skib case I915_OVERLAY_YUV422: 521235783Skib return 4; 522235783Skib case I915_OVERLAY_YUV411: 523235783Skib /* return 6; not implemented */ 524235783Skib default: 525235783Skib return -EINVAL; 526235783Skib } 527235783Skib} 528235783Skib 529235783Skibstatic int packed_width_bytes(u32 format, short width) 530235783Skib{ 531235783Skib switch (format & I915_OVERLAY_DEPTH_MASK) { 532235783Skib case I915_OVERLAY_YUV422: 533235783Skib return width << 1; 534235783Skib default: 535235783Skib return -EINVAL; 536235783Skib } 537235783Skib} 538235783Skib 539235783Skibstatic int uv_hsubsampling(u32 format) 540235783Skib{ 541235783Skib switch (format & I915_OVERLAY_DEPTH_MASK) { 542235783Skib case I915_OVERLAY_YUV422: 543235783Skib case I915_OVERLAY_YUV420: 544235783Skib return 2; 545235783Skib case I915_OVERLAY_YUV411: 546235783Skib case I915_OVERLAY_YUV410: 547235783Skib return 4; 548235783Skib default: 549235783Skib return -EINVAL; 550235783Skib } 551235783Skib} 552235783Skib 553235783Skibstatic int uv_vsubsampling(u32 format) 554235783Skib{ 555235783Skib switch (format & I915_OVERLAY_DEPTH_MASK) { 556235783Skib case I915_OVERLAY_YUV420: 557235783Skib case I915_OVERLAY_YUV410: 558235783Skib return 2; 559235783Skib case I915_OVERLAY_YUV422: 560235783Skib case I915_OVERLAY_YUV411: 561235783Skib return 1; 562235783Skib default: 563235783Skib return -EINVAL; 564235783Skib } 565235783Skib} 566235783Skib 567235783Skibstatic u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) 568235783Skib{ 569235783Skib u32 mask, shift, ret; 570235783Skib if (IS_GEN2(dev)) { 571235783Skib mask = 0x1f; 572235783Skib shift = 5; 573235783Skib } else { 574235783Skib mask = 0x3f; 575235783Skib shift = 6; 576235783Skib } 577235783Skib ret = ((offset + width + mask) >> shift) - (offset >> shift); 578235783Skib if (!IS_GEN2(dev)) 579235783Skib ret <<= 1; 580235783Skib ret -= 1; 581235783Skib return ret << 2; 582235783Skib} 583235783Skib 584235783Skibstatic const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { 585235783Skib 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0, 586235783Skib 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440, 587235783Skib 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0, 588235783Skib 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380, 589235783Skib 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320, 590235783Skib 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0, 591235783Skib 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260, 592235783Skib 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200, 593235783Skib 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0, 594235783Skib 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160, 595235783Skib 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120, 596235783Skib 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0, 597235783Skib 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0, 598235783Skib 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, 599235783Skib 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, 600235783Skib 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, 601235783Skib 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 602235783Skib}; 603235783Skib 604235783Skibstatic const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { 605235783Skib 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, 606235783Skib 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, 607235783Skib 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880, 608235783Skib 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00, 609235783Skib 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0, 610235783Skib 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, 611235783Skib 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, 612235783Skib 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, 613235783Skib 0x3000, 0x0800, 0x3000 614235783Skib}; 615235783Skib 616235783Skibstatic void update_polyphase_filter(struct overlay_registers *regs) 617235783Skib{ 618235783Skib memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs)); 619235783Skib memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs)); 620235783Skib} 621235783Skib 622235783Skibstatic bool update_scaling_factors(struct intel_overlay *overlay, 623235783Skib struct overlay_registers *regs, 624235783Skib struct put_image_params *params) 625235783Skib{ 626235783Skib /* fixed point with a 12 bit shift */ 627235783Skib u32 xscale, yscale, xscale_UV, yscale_UV; 628235783Skib#define FP_SHIFT 12 629235783Skib#define FRACT_MASK 0xfff 630235783Skib bool scale_changed = false; 631235783Skib int uv_hscale = uv_hsubsampling(params->format); 632235783Skib int uv_vscale = uv_vsubsampling(params->format); 633235783Skib 634235783Skib if (params->dst_w > 1) 635235783Skib xscale = ((params->src_scan_w - 1) << FP_SHIFT) 636235783Skib /(params->dst_w); 637235783Skib else 638235783Skib xscale = 1 << FP_SHIFT; 639235783Skib 640235783Skib if (params->dst_h > 1) 641235783Skib yscale = ((params->src_scan_h - 1) << FP_SHIFT) 642235783Skib /(params->dst_h); 643235783Skib else 644235783Skib yscale = 1 << FP_SHIFT; 645235783Skib 646235783Skib /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ 647235783Skib xscale_UV = xscale/uv_hscale; 648235783Skib yscale_UV = yscale/uv_vscale; 649235783Skib /* make the Y scale to UV scale ratio an exact multiply */ 650235783Skib xscale = xscale_UV * uv_hscale; 651235783Skib yscale = yscale_UV * uv_vscale; 652235783Skib /*} else { 653235783Skib xscale_UV = 0; 654235783Skib yscale_UV = 0; 655235783Skib }*/ 656235783Skib 657235783Skib if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) 658235783Skib scale_changed = true; 659235783Skib overlay->old_xscale = xscale; 660235783Skib overlay->old_yscale = yscale; 661235783Skib 662235783Skib regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) | 663235783Skib ((xscale >> FP_SHIFT) << 16) | 664235783Skib ((xscale & FRACT_MASK) << 3)); 665235783Skib 666235783Skib regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) | 667235783Skib ((xscale_UV >> FP_SHIFT) << 16) | 668235783Skib ((xscale_UV & FRACT_MASK) << 3)); 669235783Skib 670235783Skib regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) | 671235783Skib ((yscale_UV >> FP_SHIFT) << 0))); 672235783Skib 673235783Skib if (scale_changed) 674235783Skib update_polyphase_filter(regs); 675235783Skib 676235783Skib return scale_changed; 677235783Skib} 678235783Skib 679235783Skibstatic void update_colorkey(struct intel_overlay *overlay, 680235783Skib struct overlay_registers *regs) 681235783Skib{ 682235783Skib u32 key = overlay->color_key; 683235783Skib 684235783Skib switch (overlay->crtc->base.fb->bits_per_pixel) { 685235783Skib case 8: 686235783Skib regs->DCLRKV = 0; 687235783Skib regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; 688235783Skib break; 689235783Skib 690235783Skib case 16: 691235783Skib if (overlay->crtc->base.fb->depth == 15) { 692235783Skib regs->DCLRKV = RGB15_TO_COLORKEY(key); 693235783Skib regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; 694235783Skib } else { 695235783Skib regs->DCLRKV = RGB16_TO_COLORKEY(key); 696235783Skib regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; 697235783Skib } 698235783Skib break; 699235783Skib 700235783Skib case 24: 701235783Skib case 32: 702235783Skib regs->DCLRKV = key; 703235783Skib regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; 704235783Skib break; 705235783Skib } 706235783Skib} 707235783Skib 708235783Skibstatic u32 overlay_cmd_reg(struct put_image_params *params) 709235783Skib{ 710235783Skib u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0; 711235783Skib 712235783Skib if (params->format & I915_OVERLAY_YUV_PLANAR) { 713235783Skib switch (params->format & I915_OVERLAY_DEPTH_MASK) { 714235783Skib case I915_OVERLAY_YUV422: 715235783Skib cmd |= OCMD_YUV_422_PLANAR; 716235783Skib break; 717235783Skib case I915_OVERLAY_YUV420: 718235783Skib cmd |= OCMD_YUV_420_PLANAR; 719235783Skib break; 720235783Skib case I915_OVERLAY_YUV411: 721235783Skib case I915_OVERLAY_YUV410: 722235783Skib cmd |= OCMD_YUV_410_PLANAR; 723235783Skib break; 724235783Skib } 725235783Skib } else { /* YUV packed */ 726235783Skib switch (params->format & I915_OVERLAY_DEPTH_MASK) { 727235783Skib case I915_OVERLAY_YUV422: 728235783Skib cmd |= OCMD_YUV_422_PACKED; 729235783Skib break; 730235783Skib case I915_OVERLAY_YUV411: 731235783Skib cmd |= OCMD_YUV_411_PACKED; 732235783Skib break; 733235783Skib } 734235783Skib 735235783Skib switch (params->format & I915_OVERLAY_SWAP_MASK) { 736235783Skib case I915_OVERLAY_NO_SWAP: 737235783Skib break; 738235783Skib case I915_OVERLAY_UV_SWAP: 739235783Skib cmd |= OCMD_UV_SWAP; 740235783Skib break; 741235783Skib case I915_OVERLAY_Y_SWAP: 742235783Skib cmd |= OCMD_Y_SWAP; 743235783Skib break; 744235783Skib case I915_OVERLAY_Y_AND_UV_SWAP: 745235783Skib cmd |= OCMD_Y_AND_UV_SWAP; 746235783Skib break; 747235783Skib } 748235783Skib } 749235783Skib 750235783Skib return cmd; 751235783Skib} 752235783Skib 753235783Skibstatic u32 754235783Skibmax_u32(u32 a, u32 b) 755235783Skib{ 756235783Skib 757235783Skib return (a > b ? a : b); 758235783Skib} 759235783Skib 760235783Skibstatic int intel_overlay_do_put_image(struct intel_overlay *overlay, 761235783Skib struct drm_i915_gem_object *new_bo, 762235783Skib struct put_image_params *params) 763235783Skib{ 764235783Skib int ret, tmp_width; 765235783Skib struct overlay_registers *regs; 766235783Skib bool scale_changed = false; 767235783Skib 768235783Skib KASSERT(overlay != NULL, ("No overlay ?")); 769235783Skib DRM_LOCK_ASSERT(overlay->dev); 770235783Skib DRM_MODE_CONFIG_ASSERT_LOCKED(overlay->dev); 771235783Skib 772235783Skib ret = intel_overlay_release_old_vid(overlay); 773235783Skib if (ret != 0) 774235783Skib return ret; 775235783Skib 776235783Skib ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL); 777235783Skib if (ret != 0) 778235783Skib goto out_unpin; 779235783Skib 780235783Skib ret = i915_gem_object_put_fence(new_bo); 781235783Skib if (ret) 782235783Skib goto out_unpin; 783235783Skib 784235783Skib if (!overlay->active) { 785235783Skib regs = intel_overlay_map_regs(overlay); 786235783Skib if (!regs) { 787235783Skib ret = -ENOMEM; 788235783Skib goto out_unpin; 789235783Skib } 790235783Skib regs->OCONFIG = OCONF_CC_OUT_8BIT; 791235783Skib if (IS_GEN4(overlay->dev)) 792235783Skib regs->OCONFIG |= OCONF_CSC_MODE_BT709; 793235783Skib regs->OCONFIG |= overlay->crtc->pipe == 0 ? 794235783Skib OCONF_PIPE_A : OCONF_PIPE_B; 795235783Skib intel_overlay_unmap_regs(overlay, regs); 796235783Skib 797235783Skib ret = intel_overlay_on(overlay); 798235783Skib if (ret != 0) 799235783Skib goto out_unpin; 800235783Skib } 801235783Skib 802235783Skib regs = intel_overlay_map_regs(overlay); 803235783Skib if (!regs) { 804235783Skib ret = -ENOMEM; 805235783Skib goto out_unpin; 806235783Skib } 807235783Skib 808235783Skib regs->DWINPOS = (params->dst_y << 16) | params->dst_x; 809235783Skib regs->DWINSZ = (params->dst_h << 16) | params->dst_w; 810235783Skib 811235783Skib if (params->format & I915_OVERLAY_YUV_PACKED) 812235783Skib tmp_width = packed_width_bytes(params->format, params->src_w); 813235783Skib else 814235783Skib tmp_width = params->src_w; 815235783Skib 816235783Skib regs->SWIDTH = params->src_w; 817235783Skib regs->SWIDTHSW = calc_swidthsw(overlay->dev, 818235783Skib params->offset_Y, tmp_width); 819235783Skib regs->SHEIGHT = params->src_h; 820235783Skib regs->OBUF_0Y = new_bo->gtt_offset + params->offset_Y; 821235783Skib regs->OSTRIDE = params->stride_Y; 822235783Skib 823235783Skib if (params->format & I915_OVERLAY_YUV_PLANAR) { 824235783Skib int uv_hscale = uv_hsubsampling(params->format); 825235783Skib int uv_vscale = uv_vsubsampling(params->format); 826235783Skib u32 tmp_U, tmp_V; 827235783Skib regs->SWIDTH |= (params->src_w/uv_hscale) << 16; 828235783Skib tmp_U = calc_swidthsw(overlay->dev, params->offset_U, 829235783Skib params->src_w/uv_hscale); 830235783Skib tmp_V = calc_swidthsw(overlay->dev, params->offset_V, 831235783Skib params->src_w/uv_hscale); 832235783Skib regs->SWIDTHSW |= max_u32(tmp_U, tmp_V) << 16; 833235783Skib regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; 834235783Skib regs->OBUF_0U = new_bo->gtt_offset + params->offset_U; 835235783Skib regs->OBUF_0V = new_bo->gtt_offset + params->offset_V; 836235783Skib regs->OSTRIDE |= params->stride_UV << 16; 837235783Skib } 838235783Skib 839235783Skib scale_changed = update_scaling_factors(overlay, regs, params); 840235783Skib 841235783Skib update_colorkey(overlay, regs); 842235783Skib 843235783Skib regs->OCMD = overlay_cmd_reg(params); 844235783Skib 845235783Skib intel_overlay_unmap_regs(overlay, regs); 846235783Skib 847235783Skib ret = intel_overlay_continue(overlay, scale_changed); 848235783Skib if (ret) 849235783Skib goto out_unpin; 850235783Skib 851235783Skib overlay->old_vid_bo = overlay->vid_bo; 852235783Skib overlay->vid_bo = new_bo; 853235783Skib 854235783Skib return 0; 855235783Skib 856235783Skibout_unpin: 857235783Skib i915_gem_object_unpin(new_bo); 858235783Skib return ret; 859235783Skib} 860235783Skib 861235783Skibint intel_overlay_switch_off(struct intel_overlay *overlay) 862235783Skib{ 863235783Skib struct overlay_registers *regs; 864235783Skib int ret; 865235783Skib 866235783Skib DRM_LOCK_ASSERT(overlay->dev); 867235783Skib DRM_MODE_CONFIG_ASSERT_LOCKED(overlay->dev); 868235783Skib 869235783Skib ret = intel_overlay_recover_from_interrupt(overlay); 870235783Skib if (ret != 0) 871235783Skib return ret; 872235783Skib 873235783Skib if (!overlay->active) 874235783Skib return 0; 875235783Skib 876235783Skib ret = intel_overlay_release_old_vid(overlay); 877235783Skib if (ret != 0) 878235783Skib return ret; 879235783Skib 880235783Skib regs = intel_overlay_map_regs(overlay); 881235783Skib regs->OCMD = 0; 882235783Skib intel_overlay_unmap_regs(overlay, regs); 883235783Skib 884235783Skib ret = intel_overlay_off(overlay); 885235783Skib if (ret != 0) 886235783Skib return ret; 887235783Skib 888235783Skib intel_overlay_off_tail(overlay); 889235783Skib return 0; 890235783Skib} 891235783Skib 892235783Skibstatic int check_overlay_possible_on_crtc(struct intel_overlay *overlay, 893235783Skib struct intel_crtc *crtc) 894235783Skib{ 895235783Skib drm_i915_private_t *dev_priv = overlay->dev->dev_private; 896235783Skib 897235783Skib if (!crtc->active) 898235783Skib return -EINVAL; 899235783Skib 900235783Skib /* can't use the overlay with double wide pipe */ 901235783Skib if (INTEL_INFO(overlay->dev)->gen < 4 && 902235783Skib (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) 903235783Skib return -EINVAL; 904235783Skib 905235783Skib return 0; 906235783Skib} 907235783Skib 908235783Skibstatic void update_pfit_vscale_ratio(struct intel_overlay *overlay) 909235783Skib{ 910235783Skib struct drm_device *dev = overlay->dev; 911235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 912235783Skib u32 pfit_control = I915_READ(PFIT_CONTROL); 913235783Skib u32 ratio; 914235783Skib 915235783Skib /* XXX: This is not the same logic as in the xorg driver, but more in 916235783Skib * line with the intel documentation for the i965 917235783Skib */ 918235783Skib if (INTEL_INFO(dev)->gen >= 4) { 919235783Skib /* on i965 use the PGM reg to read out the autoscaler values */ 920235783Skib ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; 921235783Skib } else { 922235783Skib if (pfit_control & VERT_AUTO_SCALE) 923235783Skib ratio = I915_READ(PFIT_AUTO_RATIOS); 924235783Skib else 925235783Skib ratio = I915_READ(PFIT_PGM_RATIOS); 926235783Skib ratio >>= PFIT_VERT_SCALE_SHIFT; 927235783Skib } 928235783Skib 929235783Skib overlay->pfit_vscale_ratio = ratio; 930235783Skib} 931235783Skib 932235783Skibstatic int check_overlay_dst(struct intel_overlay *overlay, 933235783Skib struct drm_intel_overlay_put_image *rec) 934235783Skib{ 935235783Skib struct drm_display_mode *mode = &overlay->crtc->base.mode; 936235783Skib 937235783Skib if (rec->dst_x < mode->hdisplay && 938235783Skib rec->dst_x + rec->dst_width <= mode->hdisplay && 939235783Skib rec->dst_y < mode->vdisplay && 940235783Skib rec->dst_y + rec->dst_height <= mode->vdisplay) 941235783Skib return 0; 942235783Skib else 943235783Skib return -EINVAL; 944235783Skib} 945235783Skib 946235783Skibstatic int check_overlay_scaling(struct put_image_params *rec) 947235783Skib{ 948235783Skib u32 tmp; 949235783Skib 950235783Skib /* downscaling limit is 8.0 */ 951235783Skib tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16; 952235783Skib if (tmp > 7) 953235783Skib return -EINVAL; 954235783Skib tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16; 955235783Skib if (tmp > 7) 956235783Skib return -EINVAL; 957235783Skib 958235783Skib return 0; 959235783Skib} 960235783Skib 961235783Skibstatic int check_overlay_src(struct drm_device *dev, 962235783Skib struct drm_intel_overlay_put_image *rec, 963235783Skib struct drm_i915_gem_object *new_bo) 964235783Skib{ 965235783Skib int uv_hscale = uv_hsubsampling(rec->flags); 966235783Skib int uv_vscale = uv_vsubsampling(rec->flags); 967235783Skib u32 stride_mask; 968235783Skib int depth; 969235783Skib u32 tmp; 970235783Skib 971235783Skib /* check src dimensions */ 972235783Skib if (IS_845G(dev) || IS_I830(dev)) { 973235783Skib if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || 974235783Skib rec->src_width > IMAGE_MAX_WIDTH_LEGACY) 975235783Skib return -EINVAL; 976235783Skib } else { 977235783Skib if (rec->src_height > IMAGE_MAX_HEIGHT || 978235783Skib rec->src_width > IMAGE_MAX_WIDTH) 979235783Skib return -EINVAL; 980235783Skib } 981235783Skib 982235783Skib /* better safe than sorry, use 4 as the maximal subsampling ratio */ 983235783Skib if (rec->src_height < N_VERT_Y_TAPS*4 || 984235783Skib rec->src_width < N_HORIZ_Y_TAPS*4) 985235783Skib return -EINVAL; 986235783Skib 987235783Skib /* check alignment constraints */ 988235783Skib switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 989235783Skib case I915_OVERLAY_RGB: 990235783Skib /* not implemented */ 991235783Skib return -EINVAL; 992235783Skib 993235783Skib case I915_OVERLAY_YUV_PACKED: 994235783Skib if (uv_vscale != 1) 995235783Skib return -EINVAL; 996235783Skib 997235783Skib depth = packed_depth_bytes(rec->flags); 998235783Skib if (depth < 0) 999235783Skib return depth; 1000235783Skib 1001235783Skib /* ignore UV planes */ 1002235783Skib rec->stride_UV = 0; 1003235783Skib rec->offset_U = 0; 1004235783Skib rec->offset_V = 0; 1005235783Skib /* check pixel alignment */ 1006235783Skib if (rec->offset_Y % depth) 1007235783Skib return -EINVAL; 1008235783Skib break; 1009235783Skib 1010235783Skib case I915_OVERLAY_YUV_PLANAR: 1011235783Skib if (uv_vscale < 0 || uv_hscale < 0) 1012235783Skib return -EINVAL; 1013235783Skib /* no offset restrictions for planar formats */ 1014235783Skib break; 1015235783Skib 1016235783Skib default: 1017235783Skib return -EINVAL; 1018235783Skib } 1019235783Skib 1020235783Skib if (rec->src_width % uv_hscale) 1021235783Skib return -EINVAL; 1022235783Skib 1023235783Skib /* stride checking */ 1024235783Skib if (IS_I830(dev) || IS_845G(dev)) 1025235783Skib stride_mask = 255; 1026235783Skib else 1027235783Skib stride_mask = 63; 1028235783Skib 1029235783Skib if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) 1030235783Skib return -EINVAL; 1031235783Skib if (IS_GEN4(dev) && rec->stride_Y < 512) 1032235783Skib return -EINVAL; 1033235783Skib 1034235783Skib tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? 1035235783Skib 4096 : 8192; 1036235783Skib if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) 1037235783Skib return -EINVAL; 1038235783Skib 1039235783Skib /* check buffer dimensions */ 1040235783Skib switch (rec->flags & I915_OVERLAY_TYPE_MASK) { 1041235783Skib case I915_OVERLAY_RGB: 1042235783Skib case I915_OVERLAY_YUV_PACKED: 1043235783Skib /* always 4 Y values per depth pixels */ 1044235783Skib if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) 1045235783Skib return -EINVAL; 1046235783Skib 1047235783Skib tmp = rec->stride_Y*rec->src_height; 1048235783Skib if (rec->offset_Y + tmp > new_bo->base.size) 1049235783Skib return -EINVAL; 1050235783Skib break; 1051235783Skib 1052235783Skib case I915_OVERLAY_YUV_PLANAR: 1053235783Skib if (rec->src_width > rec->stride_Y) 1054235783Skib return -EINVAL; 1055235783Skib if (rec->src_width/uv_hscale > rec->stride_UV) 1056235783Skib return -EINVAL; 1057235783Skib 1058235783Skib tmp = rec->stride_Y * rec->src_height; 1059235783Skib if (rec->offset_Y + tmp > new_bo->base.size) 1060235783Skib return -EINVAL; 1061235783Skib 1062235783Skib tmp = rec->stride_UV * (rec->src_height / uv_vscale); 1063235783Skib if (rec->offset_U + tmp > new_bo->base.size || 1064235783Skib rec->offset_V + tmp > new_bo->base.size) 1065235783Skib return -EINVAL; 1066235783Skib break; 1067235783Skib } 1068235783Skib 1069235783Skib return 0; 1070235783Skib} 1071235783Skib 1072235783Skib/** 1073235783Skib * Return the pipe currently connected to the panel fitter, 1074235783Skib * or -1 if the panel fitter is not present or not in use 1075235783Skib */ 1076235783Skibstatic int intel_panel_fitter_pipe(struct drm_device *dev) 1077235783Skib{ 1078235783Skib struct drm_i915_private *dev_priv = dev->dev_private; 1079235783Skib u32 pfit_control; 1080235783Skib 1081235783Skib /* i830 doesn't have a panel fitter */ 1082235783Skib if (IS_I830(dev)) 1083235783Skib return -1; 1084235783Skib 1085235783Skib pfit_control = I915_READ(PFIT_CONTROL); 1086235783Skib 1087235783Skib /* See if the panel fitter is in use */ 1088235783Skib if ((pfit_control & PFIT_ENABLE) == 0) 1089235783Skib return -1; 1090235783Skib 1091235783Skib /* 965 can place panel fitter on either pipe */ 1092235783Skib if (IS_GEN4(dev)) 1093235783Skib return (pfit_control >> 29) & 0x3; 1094235783Skib 1095235783Skib /* older chips can only use pipe 1 */ 1096235783Skib return 1; 1097235783Skib} 1098235783Skib 1099235783Skibint intel_overlay_put_image(struct drm_device *dev, void *data, 1100235783Skib struct drm_file *file_priv) 1101235783Skib{ 1102235783Skib struct drm_intel_overlay_put_image *put_image_rec = data; 1103235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 1104235783Skib struct intel_overlay *overlay; 1105235783Skib struct drm_mode_object *drmmode_obj; 1106235783Skib struct intel_crtc *crtc; 1107235783Skib struct drm_i915_gem_object *new_bo; 1108235783Skib struct put_image_params *params; 1109235783Skib int ret; 1110235783Skib 1111235783Skib if (!dev_priv) { 1112235783Skib DRM_ERROR("called with no initialization\n"); 1113235783Skib return -EINVAL; 1114235783Skib } 1115235783Skib 1116235783Skib overlay = dev_priv->overlay; 1117235783Skib if (!overlay) { 1118235783Skib DRM_DEBUG("userspace bug: no overlay\n"); 1119235783Skib return -ENODEV; 1120235783Skib } 1121235783Skib 1122235783Skib if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { 1123235783Skib sx_xlock(&dev->mode_config.mutex); 1124235783Skib DRM_LOCK(dev); 1125235783Skib 1126235783Skib ret = intel_overlay_switch_off(overlay); 1127235783Skib 1128235783Skib DRM_UNLOCK(dev); 1129235783Skib sx_xunlock(&dev->mode_config.mutex); 1130235783Skib 1131235783Skib return ret; 1132235783Skib } 1133235783Skib 1134235783Skib params = malloc(sizeof(struct put_image_params), DRM_I915_GEM, 1135235783Skib M_WAITOK | M_ZERO); 1136235783Skib 1137235783Skib drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, 1138235783Skib DRM_MODE_OBJECT_CRTC); 1139235783Skib if (!drmmode_obj) { 1140235783Skib ret = -ENOENT; 1141235783Skib goto out_free; 1142235783Skib } 1143235783Skib crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); 1144235783Skib 1145235783Skib new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv, 1146235783Skib put_image_rec->bo_handle)); 1147235783Skib if (&new_bo->base == NULL) { 1148235783Skib ret = -ENOENT; 1149235783Skib goto out_free; 1150235783Skib } 1151235783Skib 1152235783Skib sx_xlock(&dev->mode_config.mutex); 1153235783Skib DRM_LOCK(dev); 1154235783Skib 1155235783Skib if (new_bo->tiling_mode) { 1156235783Skib DRM_ERROR("buffer used for overlay image can not be tiled\n"); 1157235783Skib ret = -EINVAL; 1158235783Skib goto out_unlock; 1159235783Skib } 1160235783Skib 1161235783Skib ret = intel_overlay_recover_from_interrupt(overlay); 1162235783Skib if (ret != 0) 1163235783Skib goto out_unlock; 1164235783Skib 1165235783Skib if (overlay->crtc != crtc) { 1166235783Skib struct drm_display_mode *mode = &crtc->base.mode; 1167235783Skib ret = intel_overlay_switch_off(overlay); 1168235783Skib if (ret != 0) 1169235783Skib goto out_unlock; 1170235783Skib 1171235783Skib ret = check_overlay_possible_on_crtc(overlay, crtc); 1172235783Skib if (ret != 0) 1173235783Skib goto out_unlock; 1174235783Skib 1175235783Skib overlay->crtc = crtc; 1176235783Skib crtc->overlay = overlay; 1177235783Skib 1178235783Skib /* line too wide, i.e. one-line-mode */ 1179235783Skib if (mode->hdisplay > 1024 && 1180235783Skib intel_panel_fitter_pipe(dev) == crtc->pipe) { 1181235783Skib overlay->pfit_active = 1; 1182235783Skib update_pfit_vscale_ratio(overlay); 1183235783Skib } else 1184235783Skib overlay->pfit_active = 0; 1185235783Skib } 1186235783Skib 1187235783Skib ret = check_overlay_dst(overlay, put_image_rec); 1188235783Skib if (ret != 0) 1189235783Skib goto out_unlock; 1190235783Skib 1191235783Skib if (overlay->pfit_active) { 1192235783Skib params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / 1193235783Skib overlay->pfit_vscale_ratio); 1194235783Skib /* shifting right rounds downwards, so add 1 */ 1195235783Skib params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / 1196235783Skib overlay->pfit_vscale_ratio) + 1; 1197235783Skib } else { 1198235783Skib params->dst_y = put_image_rec->dst_y; 1199235783Skib params->dst_h = put_image_rec->dst_height; 1200235783Skib } 1201235783Skib params->dst_x = put_image_rec->dst_x; 1202235783Skib params->dst_w = put_image_rec->dst_width; 1203235783Skib 1204235783Skib params->src_w = put_image_rec->src_width; 1205235783Skib params->src_h = put_image_rec->src_height; 1206235783Skib params->src_scan_w = put_image_rec->src_scan_width; 1207235783Skib params->src_scan_h = put_image_rec->src_scan_height; 1208235783Skib if (params->src_scan_h > params->src_h || 1209235783Skib params->src_scan_w > params->src_w) { 1210235783Skib ret = -EINVAL; 1211235783Skib goto out_unlock; 1212235783Skib } 1213235783Skib 1214235783Skib ret = check_overlay_src(dev, put_image_rec, new_bo); 1215235783Skib if (ret != 0) 1216235783Skib goto out_unlock; 1217235783Skib params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK; 1218235783Skib params->stride_Y = put_image_rec->stride_Y; 1219235783Skib params->stride_UV = put_image_rec->stride_UV; 1220235783Skib params->offset_Y = put_image_rec->offset_Y; 1221235783Skib params->offset_U = put_image_rec->offset_U; 1222235783Skib params->offset_V = put_image_rec->offset_V; 1223235783Skib 1224235783Skib /* Check scaling after src size to prevent a divide-by-zero. */ 1225235783Skib ret = check_overlay_scaling(params); 1226235783Skib if (ret != 0) 1227235783Skib goto out_unlock; 1228235783Skib 1229235783Skib ret = intel_overlay_do_put_image(overlay, new_bo, params); 1230235783Skib if (ret != 0) 1231235783Skib goto out_unlock; 1232235783Skib 1233235783Skib DRM_UNLOCK(dev); 1234235783Skib sx_xunlock(&dev->mode_config.mutex); 1235235783Skib 1236235783Skib free(params, DRM_I915_GEM); 1237235783Skib 1238235783Skib return 0; 1239235783Skib 1240235783Skibout_unlock: 1241235783Skib DRM_UNLOCK(dev); 1242235783Skib sx_xunlock(&dev->mode_config.mutex); 1243235783Skib drm_gem_object_unreference_unlocked(&new_bo->base); 1244235783Skibout_free: 1245235783Skib free(params, DRM_I915_GEM); 1246235783Skib 1247235783Skib return ret; 1248235783Skib} 1249235783Skib 1250235783Skibstatic void update_reg_attrs(struct intel_overlay *overlay, 1251235783Skib struct overlay_registers *regs) 1252235783Skib{ 1253235783Skib regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff); 1254235783Skib regs->OCLRC1 = overlay->saturation; 1255235783Skib} 1256235783Skib 1257235783Skibstatic bool check_gamma_bounds(u32 gamma1, u32 gamma2) 1258235783Skib{ 1259235783Skib int i; 1260235783Skib 1261235783Skib if (gamma1 & 0xff000000 || gamma2 & 0xff000000) 1262235783Skib return false; 1263235783Skib 1264235783Skib for (i = 0; i < 3; i++) { 1265235783Skib if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) 1266235783Skib return false; 1267235783Skib } 1268235783Skib 1269235783Skib return true; 1270235783Skib} 1271235783Skib 1272235783Skibstatic bool check_gamma5_errata(u32 gamma5) 1273235783Skib{ 1274235783Skib int i; 1275235783Skib 1276235783Skib for (i = 0; i < 3; i++) { 1277235783Skib if (((gamma5 >> i*8) & 0xff) == 0x80) 1278235783Skib return false; 1279235783Skib } 1280235783Skib 1281235783Skib return true; 1282235783Skib} 1283235783Skib 1284235783Skibstatic int check_gamma(struct drm_intel_overlay_attrs *attrs) 1285235783Skib{ 1286235783Skib if (!check_gamma_bounds(0, attrs->gamma0) || 1287235783Skib !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || 1288235783Skib !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || 1289235783Skib !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || 1290235783Skib !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || 1291235783Skib !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || 1292235783Skib !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) 1293235783Skib return -EINVAL; 1294235783Skib 1295235783Skib if (!check_gamma5_errata(attrs->gamma5)) 1296235783Skib return -EINVAL; 1297235783Skib 1298235783Skib return 0; 1299235783Skib} 1300235783Skib 1301235783Skibint intel_overlay_attrs(struct drm_device *dev, void *data, 1302235783Skib struct drm_file *file_priv) 1303235783Skib{ 1304235783Skib struct drm_intel_overlay_attrs *attrs = data; 1305235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 1306235783Skib struct intel_overlay *overlay; 1307235783Skib struct overlay_registers *regs; 1308235783Skib int ret; 1309235783Skib 1310235783Skib if (!dev_priv) { 1311235783Skib DRM_ERROR("called with no initialization\n"); 1312235783Skib return -EINVAL; 1313235783Skib } 1314235783Skib 1315235783Skib overlay = dev_priv->overlay; 1316235783Skib if (!overlay) { 1317235783Skib DRM_DEBUG("userspace bug: no overlay\n"); 1318235783Skib return -ENODEV; 1319235783Skib } 1320235783Skib 1321235783Skib sx_xlock(&dev->mode_config.mutex); 1322235783Skib DRM_LOCK(dev); 1323235783Skib 1324235783Skib ret = -EINVAL; 1325235783Skib if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { 1326235783Skib attrs->color_key = overlay->color_key; 1327235783Skib attrs->brightness = overlay->brightness; 1328235783Skib attrs->contrast = overlay->contrast; 1329235783Skib attrs->saturation = overlay->saturation; 1330235783Skib 1331235783Skib if (!IS_GEN2(dev)) { 1332235783Skib attrs->gamma0 = I915_READ(OGAMC0); 1333235783Skib attrs->gamma1 = I915_READ(OGAMC1); 1334235783Skib attrs->gamma2 = I915_READ(OGAMC2); 1335235783Skib attrs->gamma3 = I915_READ(OGAMC3); 1336235783Skib attrs->gamma4 = I915_READ(OGAMC4); 1337235783Skib attrs->gamma5 = I915_READ(OGAMC5); 1338235783Skib } 1339235783Skib } else { 1340235783Skib if (attrs->brightness < -128 || attrs->brightness > 127) 1341235783Skib goto out_unlock; 1342235783Skib if (attrs->contrast > 255) 1343235783Skib goto out_unlock; 1344235783Skib if (attrs->saturation > 1023) 1345235783Skib goto out_unlock; 1346235783Skib 1347235783Skib overlay->color_key = attrs->color_key; 1348235783Skib overlay->brightness = attrs->brightness; 1349235783Skib overlay->contrast = attrs->contrast; 1350235783Skib overlay->saturation = attrs->saturation; 1351235783Skib 1352235783Skib regs = intel_overlay_map_regs(overlay); 1353235783Skib if (!regs) { 1354235783Skib ret = -ENOMEM; 1355235783Skib goto out_unlock; 1356235783Skib } 1357235783Skib 1358235783Skib update_reg_attrs(overlay, regs); 1359235783Skib 1360235783Skib intel_overlay_unmap_regs(overlay, regs); 1361235783Skib 1362235783Skib if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { 1363235783Skib if (IS_GEN2(dev)) 1364235783Skib goto out_unlock; 1365235783Skib 1366235783Skib if (overlay->active) { 1367235783Skib ret = -EBUSY; 1368235783Skib goto out_unlock; 1369235783Skib } 1370235783Skib 1371235783Skib ret = check_gamma(attrs); 1372235783Skib if (ret) 1373235783Skib goto out_unlock; 1374235783Skib 1375235783Skib I915_WRITE(OGAMC0, attrs->gamma0); 1376235783Skib I915_WRITE(OGAMC1, attrs->gamma1); 1377235783Skib I915_WRITE(OGAMC2, attrs->gamma2); 1378235783Skib I915_WRITE(OGAMC3, attrs->gamma3); 1379235783Skib I915_WRITE(OGAMC4, attrs->gamma4); 1380235783Skib I915_WRITE(OGAMC5, attrs->gamma5); 1381235783Skib } 1382235783Skib } 1383235783Skib 1384235783Skib ret = 0; 1385235783Skibout_unlock: 1386235783Skib DRM_UNLOCK(dev); 1387235783Skib sx_xunlock(&dev->mode_config.mutex); 1388235783Skib 1389235783Skib return ret; 1390235783Skib} 1391235783Skib 1392235783Skibvoid intel_setup_overlay(struct drm_device *dev) 1393235783Skib{ 1394235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 1395235783Skib struct intel_overlay *overlay; 1396235783Skib struct drm_i915_gem_object *reg_bo; 1397235783Skib struct overlay_registers *regs; 1398235783Skib int ret; 1399235783Skib 1400235783Skib if (!HAS_OVERLAY(dev)) 1401235783Skib return; 1402235783Skib 1403235783Skib overlay = malloc(sizeof(struct intel_overlay), DRM_I915_GEM, 1404235783Skib M_WAITOK | M_ZERO); 1405235783Skib DRM_LOCK(dev); 1406235783Skib if (dev_priv->overlay != NULL) 1407235783Skib goto out_free; 1408235783Skib overlay->dev = dev; 1409235783Skib 1410235783Skib reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE); 1411235783Skib if (!reg_bo) 1412235783Skib goto out_free; 1413235783Skib overlay->reg_bo = reg_bo; 1414235783Skib 1415235783Skib if (OVERLAY_NEEDS_PHYSICAL(dev)) { 1416235783Skib ret = i915_gem_attach_phys_object(dev, reg_bo, 1417235783Skib I915_GEM_PHYS_OVERLAY_REGS, 1418235783Skib PAGE_SIZE); 1419235783Skib if (ret) { 1420235783Skib DRM_ERROR("failed to attach phys overlay regs\n"); 1421235783Skib goto out_free_bo; 1422235783Skib } 1423235783Skib overlay->flip_addr = reg_bo->phys_obj->handle->busaddr; 1424235783Skib } else { 1425235783Skib ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true); 1426235783Skib if (ret) { 1427235783Skib DRM_ERROR("failed to pin overlay register bo\n"); 1428235783Skib goto out_free_bo; 1429235783Skib } 1430235783Skib overlay->flip_addr = reg_bo->gtt_offset; 1431235783Skib 1432235783Skib ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); 1433235783Skib if (ret) { 1434235783Skib DRM_ERROR("failed to move overlay register bo into the GTT\n"); 1435235783Skib goto out_unpin_bo; 1436235783Skib } 1437235783Skib } 1438235783Skib 1439235783Skib /* init all values */ 1440235783Skib overlay->color_key = 0x0101fe; 1441235783Skib overlay->brightness = -19; 1442235783Skib overlay->contrast = 75; 1443235783Skib overlay->saturation = 146; 1444235783Skib 1445235783Skib regs = intel_overlay_map_regs(overlay); 1446235783Skib if (!regs) 1447235783Skib goto out_unpin_bo; 1448235783Skib 1449235783Skib memset(regs, 0, sizeof(struct overlay_registers)); 1450235783Skib update_polyphase_filter(regs); 1451235783Skib update_reg_attrs(overlay, regs); 1452235783Skib 1453235783Skib intel_overlay_unmap_regs(overlay, regs); 1454235783Skib 1455235783Skib dev_priv->overlay = overlay; 1456235783Skib DRM_INFO("initialized overlay support\n"); 1457235783Skib DRM_UNLOCK(dev); 1458235783Skib return; 1459235783Skib 1460235783Skibout_unpin_bo: 1461235783Skib if (!OVERLAY_NEEDS_PHYSICAL(dev)) 1462235783Skib i915_gem_object_unpin(reg_bo); 1463235783Skibout_free_bo: 1464235783Skib drm_gem_object_unreference(®_bo->base); 1465235783Skibout_free: 1466235783Skib DRM_UNLOCK(dev); 1467235783Skib free(overlay, DRM_I915_GEM); 1468235783Skib return; 1469235783Skib} 1470235783Skib 1471235783Skibvoid intel_cleanup_overlay(struct drm_device *dev) 1472235783Skib{ 1473235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 1474235783Skib 1475235783Skib if (!dev_priv->overlay) 1476235783Skib return; 1477235783Skib 1478235783Skib /* The bo's should be free'd by the generic code already. 1479235783Skib * Furthermore modesetting teardown happens beforehand so the 1480235783Skib * hardware should be off already */ 1481235783Skib KASSERT(!dev_priv->overlay->active, ("Overlay still active")); 1482235783Skib 1483235783Skib drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base); 1484235783Skib free(dev_priv->overlay, DRM_I915_GEM); 1485235783Skib} 1486235783Skib 1487235783Skibstruct intel_overlay_error_state { 1488235783Skib struct overlay_registers regs; 1489235783Skib unsigned long base; 1490235783Skib u32 dovsta; 1491235783Skib u32 isr; 1492235783Skib}; 1493235783Skib 1494235783Skibstruct intel_overlay_error_state * 1495235783Skibintel_overlay_capture_error_state(struct drm_device *dev) 1496235783Skib{ 1497235783Skib drm_i915_private_t *dev_priv = dev->dev_private; 1498235783Skib struct intel_overlay *overlay = dev_priv->overlay; 1499235783Skib struct intel_overlay_error_state *error; 1500235783Skib struct overlay_registers __iomem *regs; 1501235783Skib 1502235783Skib if (!overlay || !overlay->active) 1503235783Skib return NULL; 1504235783Skib 1505235783Skib error = malloc(sizeof(*error), DRM_I915_GEM, M_NOWAIT); 1506235783Skib if (error == NULL) 1507235783Skib return NULL; 1508235783Skib 1509235783Skib error->dovsta = I915_READ(DOVSTA); 1510235783Skib error->isr = I915_READ(ISR); 1511235783Skib if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) 1512235783Skib error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; 1513235783Skib else 1514235783Skib error->base = (long) overlay->reg_bo->gtt_offset; 1515235783Skib 1516235783Skib regs = intel_overlay_map_regs(overlay); 1517235783Skib if (!regs) 1518235783Skib goto err; 1519235783Skib 1520235783Skib memcpy(&error->regs, regs, sizeof(struct overlay_registers)); 1521235783Skib intel_overlay_unmap_regs(overlay, regs); 1522235783Skib 1523235783Skib return (error); 1524235783Skib 1525235783Skiberr: 1526235783Skib free(error, DRM_I915_GEM); 1527235783Skib return (NULL); 1528235783Skib} 1529235783Skib 1530235783Skibvoid 1531235783Skibintel_overlay_print_error_state(struct sbuf *m, 1532235783Skib struct intel_overlay_error_state *error) 1533235783Skib{ 1534235783Skib sbuf_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", 1535235783Skib error->dovsta, error->isr); 1536235783Skib sbuf_printf(m, " Register file at 0x%08lx:\n", 1537235783Skib error->base); 1538235783Skib 1539235783Skib#define P(x) sbuf_printf(m, " " #x ": 0x%08x\n", error->regs.x) 1540235783Skib P(OBUF_0Y); 1541235783Skib P(OBUF_1Y); 1542235783Skib P(OBUF_0U); 1543235783Skib P(OBUF_0V); 1544235783Skib P(OBUF_1U); 1545235783Skib P(OBUF_1V); 1546235783Skib P(OSTRIDE); 1547235783Skib P(YRGB_VPH); 1548235783Skib P(UV_VPH); 1549235783Skib P(HORZ_PH); 1550235783Skib P(INIT_PHS); 1551235783Skib P(DWINPOS); 1552235783Skib P(DWINSZ); 1553235783Skib P(SWIDTH); 1554235783Skib P(SWIDTHSW); 1555235783Skib P(SHEIGHT); 1556235783Skib P(YRGBSCALE); 1557235783Skib P(UVSCALE); 1558235783Skib P(OCLRC0); 1559235783Skib P(OCLRC1); 1560235783Skib P(DCLRKV); 1561235783Skib P(DCLRKM); 1562235783Skib P(SCLRKVH); 1563235783Skib P(SCLRKVL); 1564235783Skib P(SCLRKEN); 1565235783Skib P(OCONFIG); 1566235783Skib P(OCMD); 1567235783Skib P(OSTART_0Y); 1568235783Skib P(OSTART_1Y); 1569235783Skib P(OSTART_0U); 1570235783Skib P(OSTART_0V); 1571235783Skib P(OSTART_1U); 1572235783Skib P(OSTART_1V); 1573235783Skib P(OTILEOFF_0Y); 1574235783Skib P(OTILEOFF_1Y); 1575235783Skib P(OTILEOFF_0U); 1576235783Skib P(OTILEOFF_0V); 1577235783Skib P(OTILEOFF_1U); 1578235783Skib P(OTILEOFF_1V); 1579235783Skib P(FASTHSCALE); 1580235783Skib P(UVSCALEV); 1581235783Skib#undef P 1582235783Skib} 1583