Path: blob/master/drivers/gpu/drm/i915/intel_overlay.c
15113 views
/*1* Copyright © 20092*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Daniel Vetter <[email protected]>24*25* Derived from Xorg ddx, xf86-video-intel, src/i830_video.c26*/2728#include <linux/seq_file.h>29#include "drmP.h"30#include "drm.h"31#include "i915_drm.h"32#include "i915_drv.h"33#include "i915_reg.h"34#include "intel_drv.h"3536/* Limits for overlay size. According to intel doc, the real limits are:37* Y width: 4095, UV width (planar): 2047, Y height: 2047,38* UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use39* the mininum of both. */40#define IMAGE_MAX_WIDTH 204841#define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */42/* on 830 and 845 these large limits result in the card hanging */43#define IMAGE_MAX_WIDTH_LEGACY 102444#define IMAGE_MAX_HEIGHT_LEGACY 10884546/* overlay register definitions */47/* OCMD register */48#define OCMD_TILED_SURFACE (0x1<<19)49#define OCMD_MIRROR_MASK (0x3<<17)50#define OCMD_MIRROR_MODE (0x3<<17)51#define OCMD_MIRROR_HORIZONTAL (0x1<<17)52#define OCMD_MIRROR_VERTICAL (0x2<<17)53#define OCMD_MIRROR_BOTH (0x3<<17)54#define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */55#define OCMD_UV_SWAP (0x1<<14) /* YVYU */56#define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */57#define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */58#define OCMD_SOURCE_FORMAT_MASK (0xf<<10)59#define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */60#define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */61#define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */62#define OCMD_YUV_422_PACKED (0x8<<10)63#define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */64#define OCMD_YUV_420_PLANAR (0xc<<10)65#define OCMD_YUV_422_PLANAR (0xd<<10)66#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */67#define OCMD_TVSYNCFLIP_PARITY (0x1<<9)68#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)69#define OCMD_BUF_TYPE_MASK (0x1<<5)70#define OCMD_BUF_TYPE_FRAME (0x0<<5)71#define OCMD_BUF_TYPE_FIELD (0x1<<5)72#define OCMD_TEST_MODE (0x1<<4)73#define OCMD_BUFFER_SELECT (0x3<<2)74#define OCMD_BUFFER0 (0x0<<2)75#define OCMD_BUFFER1 (0x1<<2)76#define OCMD_FIELD_SELECT (0x1<<2)77#define OCMD_FIELD0 (0x0<<1)78#define OCMD_FIELD1 (0x1<<1)79#define OCMD_ENABLE (0x1<<0)8081/* OCONFIG register */82#define OCONF_PIPE_MASK (0x1<<18)83#define OCONF_PIPE_A (0x0<<18)84#define OCONF_PIPE_B (0x1<<18)85#define OCONF_GAMMA2_ENABLE (0x1<<16)86#define OCONF_CSC_MODE_BT601 (0x0<<5)87#define OCONF_CSC_MODE_BT709 (0x1<<5)88#define OCONF_CSC_BYPASS (0x1<<4)89#define OCONF_CC_OUT_8BIT (0x1<<3)90#define OCONF_TEST_MODE (0x1<<2)91#define OCONF_THREE_LINE_BUFFER (0x1<<0)92#define OCONF_TWO_LINE_BUFFER (0x0<<0)9394/* DCLRKM (dst-key) register */95#define DST_KEY_ENABLE (0x1<<31)96#define CLK_RGB24_MASK 0x097#define CLK_RGB16_MASK 0x07030798#define CLK_RGB15_MASK 0x07070799#define CLK_RGB8I_MASK 0xffffff100101#define RGB16_TO_COLORKEY(c) \102(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))103#define RGB15_TO_COLORKEY(c) \104(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))105106/* overlay flip addr flag */107#define OFC_UPDATE 0x1108109/* polyphase filter coefficients */110#define N_HORIZ_Y_TAPS 5111#define N_VERT_Y_TAPS 3112#define N_HORIZ_UV_TAPS 3113#define N_VERT_UV_TAPS 3114#define N_PHASES 17115#define MAX_TAPS 5116117/* memory bufferd overlay registers */118struct overlay_registers {119u32 OBUF_0Y;120u32 OBUF_1Y;121u32 OBUF_0U;122u32 OBUF_0V;123u32 OBUF_1U;124u32 OBUF_1V;125u32 OSTRIDE;126u32 YRGB_VPH;127u32 UV_VPH;128u32 HORZ_PH;129u32 INIT_PHS;130u32 DWINPOS;131u32 DWINSZ;132u32 SWIDTH;133u32 SWIDTHSW;134u32 SHEIGHT;135u32 YRGBSCALE;136u32 UVSCALE;137u32 OCLRC0;138u32 OCLRC1;139u32 DCLRKV;140u32 DCLRKM;141u32 SCLRKVH;142u32 SCLRKVL;143u32 SCLRKEN;144u32 OCONFIG;145u32 OCMD;146u32 RESERVED1; /* 0x6C */147u32 OSTART_0Y;148u32 OSTART_1Y;149u32 OSTART_0U;150u32 OSTART_0V;151u32 OSTART_1U;152u32 OSTART_1V;153u32 OTILEOFF_0Y;154u32 OTILEOFF_1Y;155u32 OTILEOFF_0U;156u32 OTILEOFF_0V;157u32 OTILEOFF_1U;158u32 OTILEOFF_1V;159u32 FASTHSCALE; /* 0xA0 */160u32 UVSCALEV; /* 0xA4 */161u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */162u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */163u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];164u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */165u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];166u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */167u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];168u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */169u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];170};171172struct intel_overlay {173struct drm_device *dev;174struct intel_crtc *crtc;175struct drm_i915_gem_object *vid_bo;176struct drm_i915_gem_object *old_vid_bo;177int active;178int pfit_active;179u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */180u32 color_key;181u32 brightness, contrast, saturation;182u32 old_xscale, old_yscale;183/* register access */184u32 flip_addr;185struct drm_i915_gem_object *reg_bo;186/* flip handling */187uint32_t last_flip_req;188void (*flip_tail)(struct intel_overlay *);189};190191static struct overlay_registers *192intel_overlay_map_regs(struct intel_overlay *overlay)193{194drm_i915_private_t *dev_priv = overlay->dev->dev_private;195struct overlay_registers *regs;196197if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))198regs = overlay->reg_bo->phys_obj->handle->vaddr;199else200regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,201overlay->reg_bo->gtt_offset);202203return regs;204}205206static void intel_overlay_unmap_regs(struct intel_overlay *overlay,207struct overlay_registers *regs)208{209if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))210io_mapping_unmap(regs);211}212213static int intel_overlay_do_wait_request(struct intel_overlay *overlay,214struct drm_i915_gem_request *request,215void (*tail)(struct intel_overlay *))216{217struct drm_device *dev = overlay->dev;218drm_i915_private_t *dev_priv = dev->dev_private;219int ret;220221BUG_ON(overlay->last_flip_req);222ret = i915_add_request(LP_RING(dev_priv), NULL, request);223if (ret) {224kfree(request);225return ret;226}227overlay->last_flip_req = request->seqno;228overlay->flip_tail = tail;229ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req);230if (ret)231return ret;232233overlay->last_flip_req = 0;234return 0;235}236237/* Workaround for i830 bug where pipe a must be enable to change control regs */238static int239i830_activate_pipe_a(struct drm_device *dev)240{241drm_i915_private_t *dev_priv = dev->dev_private;242struct intel_crtc *crtc;243struct drm_crtc_helper_funcs *crtc_funcs;244struct drm_display_mode vesa_640x480 = {245DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,246752, 800, 0, 480, 489, 492, 525, 0,247DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)248}, *mode;249250crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);251if (crtc->dpms_mode == DRM_MODE_DPMS_ON)252return 0;253254/* most i8xx have pipe a forced on, so don't trust dpms mode */255if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE)256return 0;257258crtc_funcs = crtc->base.helper_private;259if (crtc_funcs->dpms == NULL)260return 0;261262DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");263264mode = drm_mode_duplicate(dev, &vesa_640x480);265drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);266if(!drm_crtc_helper_set_mode(&crtc->base, mode,267crtc->base.x, crtc->base.y,268crtc->base.fb))269return 0;270271crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);272return 1;273}274275static void276i830_deactivate_pipe_a(struct drm_device *dev)277{278drm_i915_private_t *dev_priv = dev->dev_private;279struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];280struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;281282crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);283}284285/* overlay needs to be disable in OCMD reg */286static int intel_overlay_on(struct intel_overlay *overlay)287{288struct drm_device *dev = overlay->dev;289struct drm_i915_private *dev_priv = dev->dev_private;290struct drm_i915_gem_request *request;291int pipe_a_quirk = 0;292int ret;293294BUG_ON(overlay->active);295overlay->active = 1;296297if (IS_I830(dev)) {298pipe_a_quirk = i830_activate_pipe_a(dev);299if (pipe_a_quirk < 0)300return pipe_a_quirk;301}302303request = kzalloc(sizeof(*request), GFP_KERNEL);304if (request == NULL) {305ret = -ENOMEM;306goto out;307}308309ret = BEGIN_LP_RING(4);310if (ret) {311kfree(request);312goto out;313}314315OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);316OUT_RING(overlay->flip_addr | OFC_UPDATE);317OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);318OUT_RING(MI_NOOP);319ADVANCE_LP_RING();320321ret = intel_overlay_do_wait_request(overlay, request, NULL);322out:323if (pipe_a_quirk)324i830_deactivate_pipe_a(dev);325326return ret;327}328329/* overlay needs to be enabled in OCMD reg */330static int intel_overlay_continue(struct intel_overlay *overlay,331bool load_polyphase_filter)332{333struct drm_device *dev = overlay->dev;334drm_i915_private_t *dev_priv = dev->dev_private;335struct drm_i915_gem_request *request;336u32 flip_addr = overlay->flip_addr;337u32 tmp;338int ret;339340BUG_ON(!overlay->active);341342request = kzalloc(sizeof(*request), GFP_KERNEL);343if (request == NULL)344return -ENOMEM;345346if (load_polyphase_filter)347flip_addr |= OFC_UPDATE;348349/* check for underruns */350tmp = I915_READ(DOVSTA);351if (tmp & (1 << 17))352DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);353354ret = BEGIN_LP_RING(2);355if (ret) {356kfree(request);357return ret;358}359OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);360OUT_RING(flip_addr);361ADVANCE_LP_RING();362363ret = i915_add_request(LP_RING(dev_priv), NULL, request);364if (ret) {365kfree(request);366return ret;367}368369overlay->last_flip_req = request->seqno;370return 0;371}372373static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)374{375struct drm_i915_gem_object *obj = overlay->old_vid_bo;376377i915_gem_object_unpin(obj);378drm_gem_object_unreference(&obj->base);379380overlay->old_vid_bo = NULL;381}382383static void intel_overlay_off_tail(struct intel_overlay *overlay)384{385struct drm_i915_gem_object *obj = overlay->vid_bo;386387/* never have the overlay hw on without showing a frame */388BUG_ON(!overlay->vid_bo);389390i915_gem_object_unpin(obj);391drm_gem_object_unreference(&obj->base);392overlay->vid_bo = NULL;393394overlay->crtc->overlay = NULL;395overlay->crtc = NULL;396overlay->active = 0;397}398399/* overlay needs to be disabled in OCMD reg */400static int intel_overlay_off(struct intel_overlay *overlay)401{402struct drm_device *dev = overlay->dev;403struct drm_i915_private *dev_priv = dev->dev_private;404u32 flip_addr = overlay->flip_addr;405struct drm_i915_gem_request *request;406int ret;407408BUG_ON(!overlay->active);409410request = kzalloc(sizeof(*request), GFP_KERNEL);411if (request == NULL)412return -ENOMEM;413414/* According to intel docs the overlay hw may hang (when switching415* off) without loading the filter coeffs. It is however unclear whether416* this applies to the disabling of the overlay or to the switching off417* of the hw. Do it in both cases */418flip_addr |= OFC_UPDATE;419420ret = BEGIN_LP_RING(6);421if (ret) {422kfree(request);423return ret;424}425/* wait for overlay to go idle */426OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);427OUT_RING(flip_addr);428OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);429/* turn overlay off */430OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);431OUT_RING(flip_addr);432OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);433ADVANCE_LP_RING();434435return intel_overlay_do_wait_request(overlay, request,436intel_overlay_off_tail);437}438439/* recover from an interruption due to a signal440* We have to be careful not to repeat work forever an make forward progess. */441static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)442{443struct drm_device *dev = overlay->dev;444drm_i915_private_t *dev_priv = dev->dev_private;445int ret;446447if (overlay->last_flip_req == 0)448return 0;449450ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req);451if (ret)452return ret;453454if (overlay->flip_tail)455overlay->flip_tail(overlay);456457overlay->last_flip_req = 0;458return 0;459}460461/* Wait for pending overlay flip and release old frame.462* Needs to be called before the overlay register are changed463* via intel_overlay_(un)map_regs464*/465static int intel_overlay_release_old_vid(struct intel_overlay *overlay)466{467struct drm_device *dev = overlay->dev;468drm_i915_private_t *dev_priv = dev->dev_private;469int ret;470471/* Only wait if there is actually an old frame to release to472* guarantee forward progress.473*/474if (!overlay->old_vid_bo)475return 0;476477if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {478struct drm_i915_gem_request *request;479480/* synchronous slowpath */481request = kzalloc(sizeof(*request), GFP_KERNEL);482if (request == NULL)483return -ENOMEM;484485ret = BEGIN_LP_RING(2);486if (ret) {487kfree(request);488return ret;489}490491OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);492OUT_RING(MI_NOOP);493ADVANCE_LP_RING();494495ret = intel_overlay_do_wait_request(overlay, request,496intel_overlay_release_old_vid_tail);497if (ret)498return ret;499}500501intel_overlay_release_old_vid_tail(overlay);502return 0;503}504505struct put_image_params {506int format;507short dst_x;508short dst_y;509short dst_w;510short dst_h;511short src_w;512short src_scan_h;513short src_scan_w;514short src_h;515short stride_Y;516short stride_UV;517int offset_Y;518int offset_U;519int offset_V;520};521522static int packed_depth_bytes(u32 format)523{524switch (format & I915_OVERLAY_DEPTH_MASK) {525case I915_OVERLAY_YUV422:526return 4;527case I915_OVERLAY_YUV411:528/* return 6; not implemented */529default:530return -EINVAL;531}532}533534static int packed_width_bytes(u32 format, short width)535{536switch (format & I915_OVERLAY_DEPTH_MASK) {537case I915_OVERLAY_YUV422:538return width << 1;539default:540return -EINVAL;541}542}543544static int uv_hsubsampling(u32 format)545{546switch (format & I915_OVERLAY_DEPTH_MASK) {547case I915_OVERLAY_YUV422:548case I915_OVERLAY_YUV420:549return 2;550case I915_OVERLAY_YUV411:551case I915_OVERLAY_YUV410:552return 4;553default:554return -EINVAL;555}556}557558static int uv_vsubsampling(u32 format)559{560switch (format & I915_OVERLAY_DEPTH_MASK) {561case I915_OVERLAY_YUV420:562case I915_OVERLAY_YUV410:563return 2;564case I915_OVERLAY_YUV422:565case I915_OVERLAY_YUV411:566return 1;567default:568return -EINVAL;569}570}571572static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)573{574u32 mask, shift, ret;575if (IS_GEN2(dev)) {576mask = 0x1f;577shift = 5;578} else {579mask = 0x3f;580shift = 6;581}582ret = ((offset + width + mask) >> shift) - (offset >> shift);583if (!IS_GEN2(dev))584ret <<= 1;585ret -=1;586return ret << 2;587}588589static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {5900x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,5910x3000, 0xb500, 0x19d0, 0x1880, 0xb440,5920x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,5930x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,5940x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,5950x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,5960x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,5970x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,5980x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,5990x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,6000x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,6010x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,6020x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,6030x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,6040x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,6050x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,6060xb000, 0x3000, 0x0800, 0x3000, 0xb000607};608609static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {6100x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,6110xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,6120xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,6130xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,6140xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,6150xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,6160xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,6170xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,6180x3000, 0x0800, 0x3000619};620621static void update_polyphase_filter(struct overlay_registers *regs)622{623memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));624memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));625}626627static bool update_scaling_factors(struct intel_overlay *overlay,628struct overlay_registers *regs,629struct put_image_params *params)630{631/* fixed point with a 12 bit shift */632u32 xscale, yscale, xscale_UV, yscale_UV;633#define FP_SHIFT 12634#define FRACT_MASK 0xfff635bool scale_changed = false;636int uv_hscale = uv_hsubsampling(params->format);637int uv_vscale = uv_vsubsampling(params->format);638639if (params->dst_w > 1)640xscale = ((params->src_scan_w - 1) << FP_SHIFT)641/(params->dst_w);642else643xscale = 1 << FP_SHIFT;644645if (params->dst_h > 1)646yscale = ((params->src_scan_h - 1) << FP_SHIFT)647/(params->dst_h);648else649yscale = 1 << FP_SHIFT;650651/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/652xscale_UV = xscale/uv_hscale;653yscale_UV = yscale/uv_vscale;654/* make the Y scale to UV scale ratio an exact multiply */655xscale = xscale_UV * uv_hscale;656yscale = yscale_UV * uv_vscale;657/*} else {658xscale_UV = 0;659yscale_UV = 0;660}*/661662if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)663scale_changed = true;664overlay->old_xscale = xscale;665overlay->old_yscale = yscale;666667regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |668((xscale >> FP_SHIFT) << 16) |669((xscale & FRACT_MASK) << 3));670671regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |672((xscale_UV >> FP_SHIFT) << 16) |673((xscale_UV & FRACT_MASK) << 3));674675regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) |676((yscale_UV >> FP_SHIFT) << 0)));677678if (scale_changed)679update_polyphase_filter(regs);680681return scale_changed;682}683684static void update_colorkey(struct intel_overlay *overlay,685struct overlay_registers *regs)686{687u32 key = overlay->color_key;688689switch (overlay->crtc->base.fb->bits_per_pixel) {690case 8:691regs->DCLRKV = 0;692regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;693break;694695case 16:696if (overlay->crtc->base.fb->depth == 15) {697regs->DCLRKV = RGB15_TO_COLORKEY(key);698regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;699} else {700regs->DCLRKV = RGB16_TO_COLORKEY(key);701regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;702}703break;704705case 24:706case 32:707regs->DCLRKV = key;708regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;709break;710}711}712713static u32 overlay_cmd_reg(struct put_image_params *params)714{715u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;716717if (params->format & I915_OVERLAY_YUV_PLANAR) {718switch (params->format & I915_OVERLAY_DEPTH_MASK) {719case I915_OVERLAY_YUV422:720cmd |= OCMD_YUV_422_PLANAR;721break;722case I915_OVERLAY_YUV420:723cmd |= OCMD_YUV_420_PLANAR;724break;725case I915_OVERLAY_YUV411:726case I915_OVERLAY_YUV410:727cmd |= OCMD_YUV_410_PLANAR;728break;729}730} else { /* YUV packed */731switch (params->format & I915_OVERLAY_DEPTH_MASK) {732case I915_OVERLAY_YUV422:733cmd |= OCMD_YUV_422_PACKED;734break;735case I915_OVERLAY_YUV411:736cmd |= OCMD_YUV_411_PACKED;737break;738}739740switch (params->format & I915_OVERLAY_SWAP_MASK) {741case I915_OVERLAY_NO_SWAP:742break;743case I915_OVERLAY_UV_SWAP:744cmd |= OCMD_UV_SWAP;745break;746case I915_OVERLAY_Y_SWAP:747cmd |= OCMD_Y_SWAP;748break;749case I915_OVERLAY_Y_AND_UV_SWAP:750cmd |= OCMD_Y_AND_UV_SWAP;751break;752}753}754755return cmd;756}757758static int intel_overlay_do_put_image(struct intel_overlay *overlay,759struct drm_i915_gem_object *new_bo,760struct put_image_params *params)761{762int ret, tmp_width;763struct overlay_registers *regs;764bool scale_changed = false;765struct drm_device *dev = overlay->dev;766767BUG_ON(!mutex_is_locked(&dev->struct_mutex));768BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));769BUG_ON(!overlay);770771ret = intel_overlay_release_old_vid(overlay);772if (ret != 0)773return ret;774775ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true);776if (ret != 0)777return ret;778779ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);780if (ret != 0)781goto out_unpin;782783ret = i915_gem_object_put_fence(new_bo);784if (ret)785goto out_unpin;786787if (!overlay->active) {788regs = intel_overlay_map_regs(overlay);789if (!regs) {790ret = -ENOMEM;791goto out_unpin;792}793regs->OCONFIG = OCONF_CC_OUT_8BIT;794if (IS_GEN4(overlay->dev))795regs->OCONFIG |= OCONF_CSC_MODE_BT709;796regs->OCONFIG |= overlay->crtc->pipe == 0 ?797OCONF_PIPE_A : OCONF_PIPE_B;798intel_overlay_unmap_regs(overlay, regs);799800ret = intel_overlay_on(overlay);801if (ret != 0)802goto out_unpin;803}804805regs = intel_overlay_map_regs(overlay);806if (!regs) {807ret = -ENOMEM;808goto out_unpin;809}810811regs->DWINPOS = (params->dst_y << 16) | params->dst_x;812regs->DWINSZ = (params->dst_h << 16) | params->dst_w;813814if (params->format & I915_OVERLAY_YUV_PACKED)815tmp_width = packed_width_bytes(params->format, params->src_w);816else817tmp_width = params->src_w;818819regs->SWIDTH = params->src_w;820regs->SWIDTHSW = calc_swidthsw(overlay->dev,821params->offset_Y, tmp_width);822regs->SHEIGHT = params->src_h;823regs->OBUF_0Y = new_bo->gtt_offset + params-> offset_Y;824regs->OSTRIDE = params->stride_Y;825826if (params->format & I915_OVERLAY_YUV_PLANAR) {827int uv_hscale = uv_hsubsampling(params->format);828int uv_vscale = uv_vsubsampling(params->format);829u32 tmp_U, tmp_V;830regs->SWIDTH |= (params->src_w/uv_hscale) << 16;831tmp_U = calc_swidthsw(overlay->dev, params->offset_U,832params->src_w/uv_hscale);833tmp_V = calc_swidthsw(overlay->dev, params->offset_V,834params->src_w/uv_hscale);835regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;836regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;837regs->OBUF_0U = new_bo->gtt_offset + params->offset_U;838regs->OBUF_0V = new_bo->gtt_offset + params->offset_V;839regs->OSTRIDE |= params->stride_UV << 16;840}841842scale_changed = update_scaling_factors(overlay, regs, params);843844update_colorkey(overlay, regs);845846regs->OCMD = overlay_cmd_reg(params);847848intel_overlay_unmap_regs(overlay, regs);849850ret = intel_overlay_continue(overlay, scale_changed);851if (ret)852goto out_unpin;853854overlay->old_vid_bo = overlay->vid_bo;855overlay->vid_bo = new_bo;856857return 0;858859out_unpin:860i915_gem_object_unpin(new_bo);861return ret;862}863864int intel_overlay_switch_off(struct intel_overlay *overlay)865{866struct overlay_registers *regs;867struct drm_device *dev = overlay->dev;868int ret;869870BUG_ON(!mutex_is_locked(&dev->struct_mutex));871BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));872873ret = intel_overlay_recover_from_interrupt(overlay);874if (ret != 0)875return ret;876877if (!overlay->active)878return 0;879880ret = intel_overlay_release_old_vid(overlay);881if (ret != 0)882return ret;883884regs = intel_overlay_map_regs(overlay);885regs->OCMD = 0;886intel_overlay_unmap_regs(overlay, regs);887888ret = intel_overlay_off(overlay);889if (ret != 0)890return ret;891892intel_overlay_off_tail(overlay);893return 0;894}895896static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,897struct intel_crtc *crtc)898{899drm_i915_private_t *dev_priv = overlay->dev->dev_private;900901if (!crtc->active)902return -EINVAL;903904/* can't use the overlay with double wide pipe */905if (INTEL_INFO(overlay->dev)->gen < 4 &&906(I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)907return -EINVAL;908909return 0;910}911912static void update_pfit_vscale_ratio(struct intel_overlay *overlay)913{914struct drm_device *dev = overlay->dev;915drm_i915_private_t *dev_priv = dev->dev_private;916u32 pfit_control = I915_READ(PFIT_CONTROL);917u32 ratio;918919/* XXX: This is not the same logic as in the xorg driver, but more in920* line with the intel documentation for the i965921*/922if (INTEL_INFO(dev)->gen >= 4) {923/* on i965 use the PGM reg to read out the autoscaler values */924ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;925} else {926if (pfit_control & VERT_AUTO_SCALE)927ratio = I915_READ(PFIT_AUTO_RATIOS);928else929ratio = I915_READ(PFIT_PGM_RATIOS);930ratio >>= PFIT_VERT_SCALE_SHIFT;931}932933overlay->pfit_vscale_ratio = ratio;934}935936static int check_overlay_dst(struct intel_overlay *overlay,937struct drm_intel_overlay_put_image *rec)938{939struct drm_display_mode *mode = &overlay->crtc->base.mode;940941if (rec->dst_x < mode->crtc_hdisplay &&942rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&943rec->dst_y < mode->crtc_vdisplay &&944rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)945return 0;946else947return -EINVAL;948}949950static int check_overlay_scaling(struct put_image_params *rec)951{952u32 tmp;953954/* downscaling limit is 8.0 */955tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;956if (tmp > 7)957return -EINVAL;958tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;959if (tmp > 7)960return -EINVAL;961962return 0;963}964965static int check_overlay_src(struct drm_device *dev,966struct drm_intel_overlay_put_image *rec,967struct drm_i915_gem_object *new_bo)968{969int uv_hscale = uv_hsubsampling(rec->flags);970int uv_vscale = uv_vsubsampling(rec->flags);971u32 stride_mask;972int depth;973u32 tmp;974975/* check src dimensions */976if (IS_845G(dev) || IS_I830(dev)) {977if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||978rec->src_width > IMAGE_MAX_WIDTH_LEGACY)979return -EINVAL;980} else {981if (rec->src_height > IMAGE_MAX_HEIGHT ||982rec->src_width > IMAGE_MAX_WIDTH)983return -EINVAL;984}985986/* better safe than sorry, use 4 as the maximal subsampling ratio */987if (rec->src_height < N_VERT_Y_TAPS*4 ||988rec->src_width < N_HORIZ_Y_TAPS*4)989return -EINVAL;990991/* check alignment constraints */992switch (rec->flags & I915_OVERLAY_TYPE_MASK) {993case I915_OVERLAY_RGB:994/* not implemented */995return -EINVAL;996997case I915_OVERLAY_YUV_PACKED:998if (uv_vscale != 1)999return -EINVAL;10001001depth = packed_depth_bytes(rec->flags);1002if (depth < 0)1003return depth;10041005/* ignore UV planes */1006rec->stride_UV = 0;1007rec->offset_U = 0;1008rec->offset_V = 0;1009/* check pixel alignment */1010if (rec->offset_Y % depth)1011return -EINVAL;1012break;10131014case I915_OVERLAY_YUV_PLANAR:1015if (uv_vscale < 0 || uv_hscale < 0)1016return -EINVAL;1017/* no offset restrictions for planar formats */1018break;10191020default:1021return -EINVAL;1022}10231024if (rec->src_width % uv_hscale)1025return -EINVAL;10261027/* stride checking */1028if (IS_I830(dev) || IS_845G(dev))1029stride_mask = 255;1030else1031stride_mask = 63;10321033if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)1034return -EINVAL;1035if (IS_GEN4(dev) && rec->stride_Y < 512)1036return -EINVAL;10371038tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?10394096 : 8192;1040if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)1041return -EINVAL;10421043/* check buffer dimensions */1044switch (rec->flags & I915_OVERLAY_TYPE_MASK) {1045case I915_OVERLAY_RGB:1046case I915_OVERLAY_YUV_PACKED:1047/* always 4 Y values per depth pixels */1048if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)1049return -EINVAL;10501051tmp = rec->stride_Y*rec->src_height;1052if (rec->offset_Y + tmp > new_bo->base.size)1053return -EINVAL;1054break;10551056case I915_OVERLAY_YUV_PLANAR:1057if (rec->src_width > rec->stride_Y)1058return -EINVAL;1059if (rec->src_width/uv_hscale > rec->stride_UV)1060return -EINVAL;10611062tmp = rec->stride_Y * rec->src_height;1063if (rec->offset_Y + tmp > new_bo->base.size)1064return -EINVAL;10651066tmp = rec->stride_UV * (rec->src_height / uv_vscale);1067if (rec->offset_U + tmp > new_bo->base.size ||1068rec->offset_V + tmp > new_bo->base.size)1069return -EINVAL;1070break;1071}10721073return 0;1074}10751076/**1077* Return the pipe currently connected to the panel fitter,1078* or -1 if the panel fitter is not present or not in use1079*/1080static int intel_panel_fitter_pipe(struct drm_device *dev)1081{1082struct drm_i915_private *dev_priv = dev->dev_private;1083u32 pfit_control;10841085/* i830 doesn't have a panel fitter */1086if (IS_I830(dev))1087return -1;10881089pfit_control = I915_READ(PFIT_CONTROL);10901091/* See if the panel fitter is in use */1092if ((pfit_control & PFIT_ENABLE) == 0)1093return -1;10941095/* 965 can place panel fitter on either pipe */1096if (IS_GEN4(dev))1097return (pfit_control >> 29) & 0x3;10981099/* older chips can only use pipe 1 */1100return 1;1101}11021103int intel_overlay_put_image(struct drm_device *dev, void *data,1104struct drm_file *file_priv)1105{1106struct drm_intel_overlay_put_image *put_image_rec = data;1107drm_i915_private_t *dev_priv = dev->dev_private;1108struct intel_overlay *overlay;1109struct drm_mode_object *drmmode_obj;1110struct intel_crtc *crtc;1111struct drm_i915_gem_object *new_bo;1112struct put_image_params *params;1113int ret;11141115if (!dev_priv) {1116DRM_ERROR("called with no initialization\n");1117return -EINVAL;1118}11191120overlay = dev_priv->overlay;1121if (!overlay) {1122DRM_DEBUG("userspace bug: no overlay\n");1123return -ENODEV;1124}11251126if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {1127mutex_lock(&dev->mode_config.mutex);1128mutex_lock(&dev->struct_mutex);11291130ret = intel_overlay_switch_off(overlay);11311132mutex_unlock(&dev->struct_mutex);1133mutex_unlock(&dev->mode_config.mutex);11341135return ret;1136}11371138params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);1139if (!params)1140return -ENOMEM;11411142drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,1143DRM_MODE_OBJECT_CRTC);1144if (!drmmode_obj) {1145ret = -ENOENT;1146goto out_free;1147}1148crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));11491150new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv,1151put_image_rec->bo_handle));1152if (&new_bo->base == NULL) {1153ret = -ENOENT;1154goto out_free;1155}11561157mutex_lock(&dev->mode_config.mutex);1158mutex_lock(&dev->struct_mutex);11591160if (new_bo->tiling_mode) {1161DRM_ERROR("buffer used for overlay image can not be tiled\n");1162ret = -EINVAL;1163goto out_unlock;1164}11651166ret = intel_overlay_recover_from_interrupt(overlay);1167if (ret != 0)1168goto out_unlock;11691170if (overlay->crtc != crtc) {1171struct drm_display_mode *mode = &crtc->base.mode;1172ret = intel_overlay_switch_off(overlay);1173if (ret != 0)1174goto out_unlock;11751176ret = check_overlay_possible_on_crtc(overlay, crtc);1177if (ret != 0)1178goto out_unlock;11791180overlay->crtc = crtc;1181crtc->overlay = overlay;11821183/* line too wide, i.e. one-line-mode */1184if (mode->hdisplay > 1024 &&1185intel_panel_fitter_pipe(dev) == crtc->pipe) {1186overlay->pfit_active = 1;1187update_pfit_vscale_ratio(overlay);1188} else1189overlay->pfit_active = 0;1190}11911192ret = check_overlay_dst(overlay, put_image_rec);1193if (ret != 0)1194goto out_unlock;11951196if (overlay->pfit_active) {1197params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /1198overlay->pfit_vscale_ratio);1199/* shifting right rounds downwards, so add 1 */1200params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /1201overlay->pfit_vscale_ratio) + 1;1202} else {1203params->dst_y = put_image_rec->dst_y;1204params->dst_h = put_image_rec->dst_height;1205}1206params->dst_x = put_image_rec->dst_x;1207params->dst_w = put_image_rec->dst_width;12081209params->src_w = put_image_rec->src_width;1210params->src_h = put_image_rec->src_height;1211params->src_scan_w = put_image_rec->src_scan_width;1212params->src_scan_h = put_image_rec->src_scan_height;1213if (params->src_scan_h > params->src_h ||1214params->src_scan_w > params->src_w) {1215ret = -EINVAL;1216goto out_unlock;1217}12181219ret = check_overlay_src(dev, put_image_rec, new_bo);1220if (ret != 0)1221goto out_unlock;1222params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;1223params->stride_Y = put_image_rec->stride_Y;1224params->stride_UV = put_image_rec->stride_UV;1225params->offset_Y = put_image_rec->offset_Y;1226params->offset_U = put_image_rec->offset_U;1227params->offset_V = put_image_rec->offset_V;12281229/* Check scaling after src size to prevent a divide-by-zero. */1230ret = check_overlay_scaling(params);1231if (ret != 0)1232goto out_unlock;12331234ret = intel_overlay_do_put_image(overlay, new_bo, params);1235if (ret != 0)1236goto out_unlock;12371238mutex_unlock(&dev->struct_mutex);1239mutex_unlock(&dev->mode_config.mutex);12401241kfree(params);12421243return 0;12441245out_unlock:1246mutex_unlock(&dev->struct_mutex);1247mutex_unlock(&dev->mode_config.mutex);1248drm_gem_object_unreference_unlocked(&new_bo->base);1249out_free:1250kfree(params);12511252return ret;1253}12541255static void update_reg_attrs(struct intel_overlay *overlay,1256struct overlay_registers *regs)1257{1258regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);1259regs->OCLRC1 = overlay->saturation;1260}12611262static bool check_gamma_bounds(u32 gamma1, u32 gamma2)1263{1264int i;12651266if (gamma1 & 0xff000000 || gamma2 & 0xff000000)1267return false;12681269for (i = 0; i < 3; i++) {1270if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))1271return false;1272}12731274return true;1275}12761277static bool check_gamma5_errata(u32 gamma5)1278{1279int i;12801281for (i = 0; i < 3; i++) {1282if (((gamma5 >> i*8) & 0xff) == 0x80)1283return false;1284}12851286return true;1287}12881289static int check_gamma(struct drm_intel_overlay_attrs *attrs)1290{1291if (!check_gamma_bounds(0, attrs->gamma0) ||1292!check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||1293!check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||1294!check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||1295!check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||1296!check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||1297!check_gamma_bounds(attrs->gamma5, 0x00ffffff))1298return -EINVAL;12991300if (!check_gamma5_errata(attrs->gamma5))1301return -EINVAL;13021303return 0;1304}13051306int intel_overlay_attrs(struct drm_device *dev, void *data,1307struct drm_file *file_priv)1308{1309struct drm_intel_overlay_attrs *attrs = data;1310drm_i915_private_t *dev_priv = dev->dev_private;1311struct intel_overlay *overlay;1312struct overlay_registers *regs;1313int ret;13141315if (!dev_priv) {1316DRM_ERROR("called with no initialization\n");1317return -EINVAL;1318}13191320overlay = dev_priv->overlay;1321if (!overlay) {1322DRM_DEBUG("userspace bug: no overlay\n");1323return -ENODEV;1324}13251326mutex_lock(&dev->mode_config.mutex);1327mutex_lock(&dev->struct_mutex);13281329ret = -EINVAL;1330if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {1331attrs->color_key = overlay->color_key;1332attrs->brightness = overlay->brightness;1333attrs->contrast = overlay->contrast;1334attrs->saturation = overlay->saturation;13351336if (!IS_GEN2(dev)) {1337attrs->gamma0 = I915_READ(OGAMC0);1338attrs->gamma1 = I915_READ(OGAMC1);1339attrs->gamma2 = I915_READ(OGAMC2);1340attrs->gamma3 = I915_READ(OGAMC3);1341attrs->gamma4 = I915_READ(OGAMC4);1342attrs->gamma5 = I915_READ(OGAMC5);1343}1344} else {1345if (attrs->brightness < -128 || attrs->brightness > 127)1346goto out_unlock;1347if (attrs->contrast > 255)1348goto out_unlock;1349if (attrs->saturation > 1023)1350goto out_unlock;13511352overlay->color_key = attrs->color_key;1353overlay->brightness = attrs->brightness;1354overlay->contrast = attrs->contrast;1355overlay->saturation = attrs->saturation;13561357regs = intel_overlay_map_regs(overlay);1358if (!regs) {1359ret = -ENOMEM;1360goto out_unlock;1361}13621363update_reg_attrs(overlay, regs);13641365intel_overlay_unmap_regs(overlay, regs);13661367if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {1368if (IS_GEN2(dev))1369goto out_unlock;13701371if (overlay->active) {1372ret = -EBUSY;1373goto out_unlock;1374}13751376ret = check_gamma(attrs);1377if (ret)1378goto out_unlock;13791380I915_WRITE(OGAMC0, attrs->gamma0);1381I915_WRITE(OGAMC1, attrs->gamma1);1382I915_WRITE(OGAMC2, attrs->gamma2);1383I915_WRITE(OGAMC3, attrs->gamma3);1384I915_WRITE(OGAMC4, attrs->gamma4);1385I915_WRITE(OGAMC5, attrs->gamma5);1386}1387}13881389ret = 0;1390out_unlock:1391mutex_unlock(&dev->struct_mutex);1392mutex_unlock(&dev->mode_config.mutex);13931394return ret;1395}13961397void intel_setup_overlay(struct drm_device *dev)1398{1399drm_i915_private_t *dev_priv = dev->dev_private;1400struct intel_overlay *overlay;1401struct drm_i915_gem_object *reg_bo;1402struct overlay_registers *regs;1403int ret;14041405if (!HAS_OVERLAY(dev))1406return;14071408overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);1409if (!overlay)1410return;14111412mutex_lock(&dev->struct_mutex);1413if (WARN_ON(dev_priv->overlay))1414goto out_free;14151416overlay->dev = dev;14171418reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);1419if (!reg_bo)1420goto out_free;1421overlay->reg_bo = reg_bo;14221423if (OVERLAY_NEEDS_PHYSICAL(dev)) {1424ret = i915_gem_attach_phys_object(dev, reg_bo,1425I915_GEM_PHYS_OVERLAY_REGS,1426PAGE_SIZE);1427if (ret) {1428DRM_ERROR("failed to attach phys overlay regs\n");1429goto out_free_bo;1430}1431overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;1432} else {1433ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);1434if (ret) {1435DRM_ERROR("failed to pin overlay register bo\n");1436goto out_free_bo;1437}1438overlay->flip_addr = reg_bo->gtt_offset;14391440ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);1441if (ret) {1442DRM_ERROR("failed to move overlay register bo into the GTT\n");1443goto out_unpin_bo;1444}1445}14461447/* init all values */1448overlay->color_key = 0x0101fe;1449overlay->brightness = -19;1450overlay->contrast = 75;1451overlay->saturation = 146;14521453regs = intel_overlay_map_regs(overlay);1454if (!regs)1455goto out_unpin_bo;14561457memset(regs, 0, sizeof(struct overlay_registers));1458update_polyphase_filter(regs);1459update_reg_attrs(overlay, regs);14601461intel_overlay_unmap_regs(overlay, regs);14621463dev_priv->overlay = overlay;1464mutex_unlock(&dev->struct_mutex);1465DRM_INFO("initialized overlay support\n");1466return;14671468out_unpin_bo:1469if (!OVERLAY_NEEDS_PHYSICAL(dev))1470i915_gem_object_unpin(reg_bo);1471out_free_bo:1472drm_gem_object_unreference(®_bo->base);1473out_free:1474mutex_unlock(&dev->struct_mutex);1475kfree(overlay);1476return;1477}14781479void intel_cleanup_overlay(struct drm_device *dev)1480{1481drm_i915_private_t *dev_priv = dev->dev_private;14821483if (!dev_priv->overlay)1484return;14851486/* The bo's should be free'd by the generic code already.1487* Furthermore modesetting teardown happens beforehand so the1488* hardware should be off already */1489BUG_ON(dev_priv->overlay->active);14901491drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);1492kfree(dev_priv->overlay);1493}14941495#ifdef CONFIG_DEBUG_FS1496#include <linux/seq_file.h>14971498struct intel_overlay_error_state {1499struct overlay_registers regs;1500unsigned long base;1501u32 dovsta;1502u32 isr;1503};15041505static struct overlay_registers *1506intel_overlay_map_regs_atomic(struct intel_overlay *overlay)1507{1508drm_i915_private_t *dev_priv = overlay->dev->dev_private;1509struct overlay_registers *regs;15101511if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))1512regs = overlay->reg_bo->phys_obj->handle->vaddr;1513else1514regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,1515overlay->reg_bo->gtt_offset);15161517return regs;1518}15191520static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,1521struct overlay_registers *regs)1522{1523if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))1524io_mapping_unmap_atomic(regs);1525}152615271528struct intel_overlay_error_state *1529intel_overlay_capture_error_state(struct drm_device *dev)1530{1531drm_i915_private_t *dev_priv = dev->dev_private;1532struct intel_overlay *overlay = dev_priv->overlay;1533struct intel_overlay_error_state *error;1534struct overlay_registers __iomem *regs;15351536if (!overlay || !overlay->active)1537return NULL;15381539error = kmalloc(sizeof(*error), GFP_ATOMIC);1540if (error == NULL)1541return NULL;15421543error->dovsta = I915_READ(DOVSTA);1544error->isr = I915_READ(ISR);1545if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))1546error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;1547else1548error->base = (long) overlay->reg_bo->gtt_offset;15491550regs = intel_overlay_map_regs_atomic(overlay);1551if (!regs)1552goto err;15531554memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));1555intel_overlay_unmap_regs_atomic(overlay, regs);15561557return error;15581559err:1560kfree(error);1561return NULL;1562}15631564void1565intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)1566{1567seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",1568error->dovsta, error->isr);1569seq_printf(m, " Register file at 0x%08lx:\n",1570error->base);15711572#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)1573P(OBUF_0Y);1574P(OBUF_1Y);1575P(OBUF_0U);1576P(OBUF_0V);1577P(OBUF_1U);1578P(OBUF_1V);1579P(OSTRIDE);1580P(YRGB_VPH);1581P(UV_VPH);1582P(HORZ_PH);1583P(INIT_PHS);1584P(DWINPOS);1585P(DWINSZ);1586P(SWIDTH);1587P(SWIDTHSW);1588P(SHEIGHT);1589P(YRGBSCALE);1590P(UVSCALE);1591P(OCLRC0);1592P(OCLRC1);1593P(DCLRKV);1594P(DCLRKM);1595P(SCLRKVH);1596P(SCLRKVL);1597P(SCLRKEN);1598P(OCONFIG);1599P(OCMD);1600P(OSTART_0Y);1601P(OSTART_1Y);1602P(OSTART_0U);1603P(OSTART_0V);1604P(OSTART_1U);1605P(OSTART_1V);1606P(OTILEOFF_0Y);1607P(OTILEOFF_1Y);1608P(OTILEOFF_0U);1609P(OTILEOFF_0V);1610P(OTILEOFF_1U);1611P(OTILEOFF_1V);1612P(FASTHSCALE);1613P(UVSCALEV);1614#undef P1615}1616#endif161716181619