LCOV - code coverage report
Current view: top level - dev/pci/drm/i915 - intel_overlay.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 707 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 38 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13