2009-09-16 00:57:34 +04:00
/*
* Copyright © 2009
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
* Authors :
* Daniel Vetter < daniel @ ffwll . ch >
*
* Derived from Xorg ddx , xf86 - video - intel , src / i830_video . c
*/
# include "drmP.h"
# include "drm.h"
# include "i915_drm.h"
# include "i915_drv.h"
# include "i915_reg.h"
# include "intel_drv.h"
/* Limits for overlay size. According to intel doc, the real limits are:
* Y width : 4095 , UV width ( planar ) : 2047 , Y height : 2047 ,
* UV width ( planar ) : * 1023. But the xorg thinks 2048 for height and width . Use
* the mininum of both . */
# define IMAGE_MAX_WIDTH 2048
# define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
/* on 830 and 845 these large limits result in the card hanging */
# define IMAGE_MAX_WIDTH_LEGACY 1024
# define IMAGE_MAX_HEIGHT_LEGACY 1088
/* overlay register definitions */
/* OCMD register */
# define OCMD_TILED_SURFACE (0x1<<19)
# define OCMD_MIRROR_MASK (0x3<<17)
# define OCMD_MIRROR_MODE (0x3<<17)
# define OCMD_MIRROR_HORIZONTAL (0x1<<17)
# define OCMD_MIRROR_VERTICAL (0x2<<17)
# define OCMD_MIRROR_BOTH (0x3<<17)
# define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
# define OCMD_UV_SWAP (0x1<<14) /* YVYU */
# define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
# define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
# define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
# define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
# define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
# define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
# define OCMD_YUV_422_PACKED (0x8<<10)
# define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
# define OCMD_YUV_420_PLANAR (0xc<<10)
# define OCMD_YUV_422_PLANAR (0xd<<10)
# define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
# define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
# define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
2010-07-13 16:52:17 +04:00
# define OCMD_BUF_TYPE_MASK (0x1<<5)
2009-09-16 00:57:34 +04:00
# define OCMD_BUF_TYPE_FRAME (0x0<<5)
# define OCMD_BUF_TYPE_FIELD (0x1<<5)
# define OCMD_TEST_MODE (0x1<<4)
# define OCMD_BUFFER_SELECT (0x3<<2)
# define OCMD_BUFFER0 (0x0<<2)
# define OCMD_BUFFER1 (0x1<<2)
# define OCMD_FIELD_SELECT (0x1<<2)
# define OCMD_FIELD0 (0x0<<1)
# define OCMD_FIELD1 (0x1<<1)
# define OCMD_ENABLE (0x1<<0)
/* OCONFIG register */
# define OCONF_PIPE_MASK (0x1<<18)
# define OCONF_PIPE_A (0x0<<18)
# define OCONF_PIPE_B (0x1<<18)
# define OCONF_GAMMA2_ENABLE (0x1<<16)
# define OCONF_CSC_MODE_BT601 (0x0<<5)
# define OCONF_CSC_MODE_BT709 (0x1<<5)
# define OCONF_CSC_BYPASS (0x1<<4)
# define OCONF_CC_OUT_8BIT (0x1<<3)
# define OCONF_TEST_MODE (0x1<<2)
# define OCONF_THREE_LINE_BUFFER (0x1<<0)
# define OCONF_TWO_LINE_BUFFER (0x0<<0)
/* DCLRKM (dst-key) register */
# define DST_KEY_ENABLE (0x1<<31)
# define CLK_RGB24_MASK 0x0
# define CLK_RGB16_MASK 0x070307
# define CLK_RGB15_MASK 0x070707
# define CLK_RGB8I_MASK 0xffffff
# define RGB16_TO_COLORKEY(c) \
( ( ( c & 0xF800 ) < < 8 ) | ( ( c & 0x07E0 ) < < 5 ) | ( ( c & 0x001F ) < < 3 ) )
# define RGB15_TO_COLORKEY(c) \
( ( ( c & 0x7c00 ) < < 9 ) | ( ( c & 0x03E0 ) < < 6 ) | ( ( c & 0x001F ) < < 3 ) )
/* overlay flip addr flag */
# define OFC_UPDATE 0x1
/* polyphase filter coefficients */
# define N_HORIZ_Y_TAPS 5
# define N_VERT_Y_TAPS 3
# define N_HORIZ_UV_TAPS 3
# define N_VERT_UV_TAPS 3
# define N_PHASES 17
# define MAX_TAPS 5
/* memory bufferd overlay registers */
struct overlay_registers {
2011-08-16 23:34:10 +04:00
u32 OBUF_0Y ;
u32 OBUF_1Y ;
u32 OBUF_0U ;
u32 OBUF_0V ;
u32 OBUF_1U ;
u32 OBUF_1V ;
u32 OSTRIDE ;
u32 YRGB_VPH ;
u32 UV_VPH ;
u32 HORZ_PH ;
u32 INIT_PHS ;
u32 DWINPOS ;
u32 DWINSZ ;
u32 SWIDTH ;
u32 SWIDTHSW ;
u32 SHEIGHT ;
u32 YRGBSCALE ;
u32 UVSCALE ;
u32 OCLRC0 ;
u32 OCLRC1 ;
u32 DCLRKV ;
u32 DCLRKM ;
u32 SCLRKVH ;
u32 SCLRKVL ;
u32 SCLRKEN ;
u32 OCONFIG ;
u32 OCMD ;
u32 RESERVED1 ; /* 0x6C */
u32 OSTART_0Y ;
u32 OSTART_1Y ;
u32 OSTART_0U ;
u32 OSTART_0V ;
u32 OSTART_1U ;
u32 OSTART_1V ;
u32 OTILEOFF_0Y ;
u32 OTILEOFF_1Y ;
u32 OTILEOFF_0U ;
u32 OTILEOFF_0V ;
u32 OTILEOFF_1U ;
u32 OTILEOFF_1V ;
u32 FASTHSCALE ; /* 0xA0 */
u32 UVSCALEV ; /* 0xA4 */
u32 RESERVEDC [ ( 0x200 - 0xA8 ) / 4 ] ; /* 0xA8 - 0x1FC */
u16 Y_VCOEFS [ N_VERT_Y_TAPS * N_PHASES ] ; /* 0x200 */
u16 RESERVEDD [ 0x100 / 2 - N_VERT_Y_TAPS * N_PHASES ] ;
u16 Y_HCOEFS [ N_HORIZ_Y_TAPS * N_PHASES ] ; /* 0x300 */
u16 RESERVEDE [ 0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES ] ;
u16 UV_VCOEFS [ N_VERT_UV_TAPS * N_PHASES ] ; /* 0x500 */
u16 RESERVEDF [ 0x100 / 2 - N_VERT_UV_TAPS * N_PHASES ] ;
u16 UV_HCOEFS [ N_HORIZ_UV_TAPS * N_PHASES ] ; /* 0x600 */
u16 RESERVEDG [ 0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES ] ;
2009-09-16 00:57:34 +04:00
} ;
2010-08-12 16:53:37 +04:00
struct intel_overlay {
struct drm_device * dev ;
struct intel_crtc * crtc ;
struct drm_i915_gem_object * vid_bo ;
struct drm_i915_gem_object * old_vid_bo ;
int active ;
int pfit_active ;
u32 pfit_vscale_ratio ; /* shifted-point number, (1<<12) == 1.0 */
u32 color_key ;
u32 brightness , contrast , saturation ;
u32 old_xscale , old_yscale ;
/* register access */
u32 flip_addr ;
struct drm_i915_gem_object * reg_bo ;
/* flip handling */
uint32_t last_flip_req ;
2010-08-12 17:03:48 +04:00
void ( * flip_tail ) ( struct intel_overlay * ) ;
2010-08-12 16:53:37 +04:00
} ;
2009-09-16 00:57:34 +04:00
2012-04-17 01:07:43 +04:00
static struct overlay_registers __iomem *
2010-08-12 13:35:26 +04:00
intel_overlay_map_regs ( struct intel_overlay * overlay )
2009-09-16 00:57:34 +04:00
{
2011-08-16 23:34:10 +04:00
drm_i915_private_t * dev_priv = overlay - > dev - > dev_private ;
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ;
2009-09-16 00:57:34 +04:00
2010-08-12 15:02:11 +04:00
if ( OVERLAY_NEEDS_PHYSICAL ( overlay - > dev ) )
2012-04-17 01:07:43 +04:00
regs = ( struct overlay_registers __iomem * ) overlay - > reg_bo - > phys_obj - > handle - > vaddr ;
2010-08-12 15:02:11 +04:00
else
2010-08-12 13:35:26 +04:00
regs = io_mapping_map_wc ( dev_priv - > mm . gtt_mapping ,
overlay - > reg_bo - > gtt_offset ) ;
2009-09-16 00:57:34 +04:00
2010-08-12 15:02:11 +04:00
return regs ;
2010-08-12 13:35:26 +04:00
}
2009-09-16 00:57:34 +04:00
2010-08-12 15:02:11 +04:00
static void intel_overlay_unmap_regs ( struct intel_overlay * overlay ,
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs )
2010-08-12 13:35:26 +04:00
{
if ( ! OVERLAY_NEEDS_PHYSICAL ( overlay - > dev ) )
2010-08-12 15:02:11 +04:00
io_mapping_unmap ( regs ) ;
2009-09-16 00:57:34 +04:00
}
2010-08-12 14:55:08 +04:00
static int intel_overlay_do_wait_request ( struct intel_overlay * overlay ,
2010-08-12 15:36:12 +04:00
struct drm_i915_gem_request * request ,
2010-08-12 17:03:48 +04:00
void ( * tail ) ( struct intel_overlay * ) )
2009-09-16 00:57:34 +04:00
{
struct drm_device * dev = overlay - > dev ;
2010-05-21 05:08:56 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2010-08-12 14:55:08 +04:00
int ret ;
2009-09-16 00:57:34 +04:00
2010-08-12 17:03:48 +04:00
BUG_ON ( overlay - > last_flip_req ) ;
2011-02-03 14:57:46 +03:00
ret = i915_add_request ( LP_RING ( dev_priv ) , NULL , request ) ;
2010-10-27 19:11:02 +04:00
if ( ret ) {
kfree ( request ) ;
return ret ;
}
overlay - > last_flip_req = request - > seqno ;
2010-08-12 17:03:48 +04:00
overlay - > flip_tail = tail ;
2012-01-26 03:39:34 +04:00
ret = i915_wait_request ( LP_RING ( dev_priv ) , overlay - > last_flip_req ,
true ) ;
2010-08-12 14:55:08 +04:00
if ( ret )
2009-09-16 00:57:37 +04:00
return ret ;
2009-09-16 00:57:34 +04:00
2009-09-16 00:57:37 +04:00
overlay - > last_flip_req = 0 ;
2009-09-16 00:57:34 +04:00
return 0 ;
}
2010-07-16 20:13:01 +04:00
/* Workaround for i830 bug where pipe a must be enable to change control regs */
static int
i830_activate_pipe_a ( struct drm_device * dev )
2009-09-16 00:57:34 +04:00
{
2010-07-16 20:13:01 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
struct intel_crtc * crtc ;
struct drm_crtc_helper_funcs * crtc_funcs ;
struct drm_display_mode vesa_640x480 = {
DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 25175 , 640 , 656 ,
752 , 800 , 0 , 480 , 489 , 492 , 525 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC )
} , * mode ;
crtc = to_intel_crtc ( dev_priv - > pipe_to_crtc_mapping [ 0 ] ) ;
if ( crtc - > dpms_mode = = DRM_MODE_DPMS_ON )
return 0 ;
2009-09-16 00:57:34 +04:00
2010-07-16 20:13:01 +04:00
/* most i8xx have pipe a forced on, so don't trust dpms mode */
2011-02-07 23:26:52 +03:00
if ( I915_READ ( _PIPEACONF ) & PIPECONF_ENABLE )
2010-07-16 20:13:01 +04:00
return 0 ;
2009-09-16 00:57:34 +04:00
2010-07-16 20:13:01 +04:00
crtc_funcs = crtc - > base . helper_private ;
if ( crtc_funcs - > dpms = = NULL )
return 0 ;
DRM_DEBUG_DRIVER ( " Enabling pipe A in order to enable overlay \n " ) ;
mode = drm_mode_duplicate ( dev , & vesa_640x480 ) ;
2012-01-28 17:49:20 +04:00
drm_mode_set_crtcinfo ( mode , 0 ) ;
2011-08-16 23:34:10 +04:00
if ( ! drm_crtc_helper_set_mode ( & crtc - > base , mode ,
2010-07-16 20:13:01 +04:00
crtc - > base . x , crtc - > base . y ,
crtc - > base . fb ) )
return 0 ;
crtc_funcs - > dpms ( & crtc - > base , DRM_MODE_DPMS_ON ) ;
return 1 ;
}
static void
i830_deactivate_pipe_a ( struct drm_device * dev )
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
struct drm_crtc * crtc = dev_priv - > pipe_to_crtc_mapping [ 0 ] ;
struct drm_crtc_helper_funcs * crtc_funcs = crtc - > helper_private ;
crtc_funcs - > dpms ( crtc , DRM_MODE_DPMS_OFF ) ;
2009-09-16 00:57:34 +04:00
}
/* overlay needs to be disable in OCMD reg */
static int intel_overlay_on ( struct intel_overlay * overlay )
{
struct drm_device * dev = overlay - > dev ;
2010-10-27 15:45:26 +04:00
struct drm_i915_private * dev_priv = dev - > dev_private ;
2010-08-12 15:36:12 +04:00
struct drm_i915_gem_request * request ;
2010-07-16 20:13:01 +04:00
int pipe_a_quirk = 0 ;
2009-09-16 00:57:34 +04:00
int ret ;
BUG_ON ( overlay - > active ) ;
2009-09-16 00:57:37 +04:00
overlay - > active = 1 ;
2010-08-12 14:55:08 +04:00
2010-07-16 20:13:01 +04:00
if ( IS_I830 ( dev ) ) {
pipe_a_quirk = i830_activate_pipe_a ( dev ) ;
if ( pipe_a_quirk < 0 )
return pipe_a_quirk ;
}
2010-08-12 15:36:12 +04:00
request = kzalloc ( sizeof ( * request ) , GFP_KERNEL ) ;
2010-07-16 20:13:01 +04:00
if ( request = = NULL ) {
ret = - ENOMEM ;
goto out ;
}
2009-09-16 00:57:37 +04:00
2010-10-27 15:45:26 +04:00
ret = BEGIN_LP_RING ( 4 ) ;
if ( ret ) {
kfree ( request ) ;
goto out ;
}
2009-09-16 00:57:34 +04:00
OUT_RING ( MI_OVERLAY_FLIP | MI_OVERLAY_ON ) ;
OUT_RING ( overlay - > flip_addr | OFC_UPDATE ) ;
OUT_RING ( MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ) ;
OUT_RING ( MI_NOOP ) ;
ADVANCE_LP_RING ( ) ;
2011-02-21 17:43:56 +03:00
ret = intel_overlay_do_wait_request ( overlay , request , NULL ) ;
2010-07-16 20:13:01 +04:00
out :
if ( pipe_a_quirk )
i830_deactivate_pipe_a ( dev ) ;
2009-09-16 00:57:34 +04:00
2010-07-16 20:13:01 +04:00
return ret ;
2009-09-16 00:57:34 +04:00
}
/* overlay needs to be enabled in OCMD reg */
2010-08-12 15:36:12 +04:00
static int intel_overlay_continue ( struct intel_overlay * overlay ,
bool load_polyphase_filter )
2009-09-16 00:57:34 +04:00
{
struct drm_device * dev = overlay - > dev ;
2011-08-16 23:34:10 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2010-08-12 15:36:12 +04:00
struct drm_i915_gem_request * request ;
2009-09-16 00:57:34 +04:00
u32 flip_addr = overlay - > flip_addr ;
u32 tmp ;
2010-10-27 15:45:26 +04:00
int ret ;
2009-09-16 00:57:34 +04:00
BUG_ON ( ! overlay - > active ) ;
2010-08-12 15:36:12 +04:00
request = kzalloc ( sizeof ( * request ) , GFP_KERNEL ) ;
if ( request = = NULL )
return - ENOMEM ;
2009-09-16 00:57:34 +04:00
if ( load_polyphase_filter )
flip_addr | = OFC_UPDATE ;
/* check for underruns */
tmp = I915_READ ( DOVSTA ) ;
if ( tmp & ( 1 < < 17 ) )
DRM_DEBUG ( " overlay underrun, DOVSTA: %x \n " , tmp ) ;
2010-10-27 15:45:26 +04:00
ret = BEGIN_LP_RING ( 2 ) ;
if ( ret ) {
kfree ( request ) ;
return ret ;
}
2009-09-16 00:57:34 +04:00
OUT_RING ( MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE ) ;
OUT_RING ( flip_addr ) ;
2011-08-16 23:34:10 +04:00
ADVANCE_LP_RING ( ) ;
2009-09-16 00:57:36 +04:00
2011-02-03 14:57:46 +03:00
ret = i915_add_request ( LP_RING ( dev_priv ) , NULL , request ) ;
2010-10-27 19:11:02 +04:00
if ( ret ) {
kfree ( request ) ;
return ret ;
}
overlay - > last_flip_req = request - > seqno ;
2010-08-12 15:36:12 +04:00
return 0 ;
2009-09-16 00:57:36 +04:00
}
2010-08-12 17:03:48 +04:00
static void intel_overlay_release_old_vid_tail ( struct intel_overlay * overlay )
2009-09-16 00:57:36 +04:00
{
2010-11-08 22:18:58 +03:00
struct drm_i915_gem_object * obj = overlay - > old_vid_bo ;
2009-09-16 00:57:36 +04:00
2010-08-12 17:03:48 +04:00
i915_gem_object_unpin ( obj ) ;
2010-11-08 22:18:58 +03:00
drm_gem_object_unreference ( & obj - > base ) ;
2009-09-16 00:57:36 +04:00
2010-08-12 17:03:48 +04:00
overlay - > old_vid_bo = NULL ;
}
2009-09-16 00:57:37 +04:00
2010-08-12 17:03:48 +04:00
static void intel_overlay_off_tail ( struct intel_overlay * overlay )
{
2010-11-08 22:18:58 +03:00
struct drm_i915_gem_object * obj = overlay - > vid_bo ;
2009-09-16 00:57:34 +04:00
2010-08-12 17:03:48 +04:00
/* never have the overlay hw on without showing a frame */
BUG_ON ( ! overlay - > vid_bo ) ;
2009-09-16 00:57:34 +04:00
2010-08-12 17:03:48 +04:00
i915_gem_object_unpin ( obj ) ;
2010-11-08 22:18:58 +03:00
drm_gem_object_unreference ( & obj - > base ) ;
2010-08-12 17:03:48 +04:00
overlay - > vid_bo = NULL ;
2009-09-16 00:57:37 +04:00
2010-08-12 17:03:48 +04:00
overlay - > crtc - > overlay = NULL ;
overlay - > crtc = NULL ;
overlay - > active = 0 ;
2009-09-16 00:57:34 +04:00
}
/* overlay needs to be disabled in OCMD reg */
2011-02-21 17:43:56 +03:00
static int intel_overlay_off ( struct intel_overlay * overlay )
2009-09-16 00:57:34 +04:00
{
struct drm_device * dev = overlay - > dev ;
2010-10-27 15:45:26 +04:00
struct drm_i915_private * dev_priv = dev - > dev_private ;
2010-08-12 15:36:12 +04:00
u32 flip_addr = overlay - > flip_addr ;
struct drm_i915_gem_request * request ;
2010-10-27 15:45:26 +04:00
int ret ;
2009-09-16 00:57:34 +04:00
BUG_ON ( ! overlay - > active ) ;
2010-08-12 15:36:12 +04:00
request = kzalloc ( sizeof ( * request ) , GFP_KERNEL ) ;
if ( request = = NULL )
return - ENOMEM ;
2009-09-16 00:57:34 +04:00
/* According to intel docs the overlay hw may hang (when switching
* off ) without loading the filter coeffs . It is however unclear whether
* this applies to the disabling of the overlay or to the switching off
* of the hw . Do it in both cases */
flip_addr | = OFC_UPDATE ;
2010-10-27 15:45:26 +04:00
ret = BEGIN_LP_RING ( 6 ) ;
if ( ret ) {
kfree ( request ) ;
return ret ;
}
2009-09-16 00:57:34 +04:00
/* wait for overlay to go idle */
OUT_RING ( MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE ) ;
OUT_RING ( flip_addr ) ;
2010-08-12 12:28:50 +04:00
OUT_RING ( MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ) ;
2009-09-16 00:57:34 +04:00
/* turn overlay off */
2010-08-12 12:28:50 +04:00
OUT_RING ( MI_OVERLAY_FLIP | MI_OVERLAY_OFF ) ;
2009-09-16 00:57:34 +04:00
OUT_RING ( flip_addr ) ;
2010-08-12 12:28:50 +04:00
OUT_RING ( MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ) ;
2009-09-16 00:57:34 +04:00
ADVANCE_LP_RING ( ) ;
2011-02-21 17:43:56 +03:00
return intel_overlay_do_wait_request ( overlay , request ,
2010-08-12 17:03:48 +04:00
intel_overlay_off_tail ) ;
2037-04-25 11:08:26 +03:00
}
2009-09-16 00:57:37 +04:00
/* recover from an interruption due to a signal
* We have to be careful not to repeat work forever an make forward progess . */
2011-02-21 17:43:56 +03:00
static int intel_overlay_recover_from_interrupt ( struct intel_overlay * overlay )
2009-09-16 00:57:37 +04:00
{
struct drm_device * dev = overlay - > dev ;
2010-05-21 05:08:56 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2009-09-16 00:57:37 +04:00
int ret ;
2010-08-12 17:03:48 +04:00
if ( overlay - > last_flip_req = = 0 )
return 0 ;
2009-09-16 00:57:37 +04:00
2012-01-26 03:39:34 +04:00
ret = i915_wait_request ( LP_RING ( dev_priv ) , overlay - > last_flip_req ,
true ) ;
2010-08-12 14:55:08 +04:00
if ( ret )
2009-09-16 00:57:37 +04:00
return ret ;
2010-08-12 17:03:48 +04:00
if ( overlay - > flip_tail )
overlay - > flip_tail ( overlay ) ;
2009-09-16 00:57:37 +04:00
overlay - > last_flip_req = 0 ;
return 0 ;
}
2009-09-16 00:57:36 +04:00
/* Wait for pending overlay flip and release old frame.
* Needs to be called before the overlay register are changed
2010-08-12 13:35:26 +04:00
* via intel_overlay_ ( un ) map_regs
*/
2009-09-16 00:57:34 +04:00
static int intel_overlay_release_old_vid ( struct intel_overlay * overlay )
{
2010-08-12 15:21:54 +04:00
struct drm_device * dev = overlay - > dev ;
drm_i915_private_t * dev_priv = dev - > dev_private ;
2009-09-16 00:57:34 +04:00
int ret ;
2010-08-12 15:21:54 +04:00
/* Only wait if there is actually an old frame to release to
* guarantee forward progress .
*/
2009-09-16 00:57:37 +04:00
if ( ! overlay - > old_vid_bo )
return 0 ;
2010-08-12 15:21:54 +04:00
if ( I915_READ ( ISR ) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT ) {
2010-08-12 15:36:12 +04:00
struct drm_i915_gem_request * request ;
2009-09-16 00:57:34 +04:00
2010-08-12 15:21:54 +04:00
/* synchronous slowpath */
2010-08-12 15:36:12 +04:00
request = kzalloc ( sizeof ( * request ) , GFP_KERNEL ) ;
if ( request = = NULL )
return - ENOMEM ;
2009-09-16 00:57:34 +04:00
2010-10-27 15:45:26 +04:00
ret = BEGIN_LP_RING ( 2 ) ;
if ( ret ) {
kfree ( request ) ;
return ret ;
}
2010-08-12 15:21:54 +04:00
OUT_RING ( MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ) ;
OUT_RING ( MI_NOOP ) ;
ADVANCE_LP_RING ( ) ;
2011-02-21 17:43:56 +03:00
ret = intel_overlay_do_wait_request ( overlay , request ,
2010-08-12 17:03:48 +04:00
intel_overlay_release_old_vid_tail ) ;
2010-08-12 15:21:54 +04:00
if ( ret )
return ret ;
}
2009-09-16 00:57:34 +04:00
2010-08-12 15:21:54 +04:00
intel_overlay_release_old_vid_tail ( overlay ) ;
2009-09-16 00:57:34 +04:00
return 0 ;
}
struct put_image_params {
int format ;
short dst_x ;
short dst_y ;
short dst_w ;
short dst_h ;
short src_w ;
short src_scan_h ;
short src_scan_w ;
short src_h ;
short stride_Y ;
short stride_UV ;
int offset_Y ;
int offset_U ;
int offset_V ;
} ;
static int packed_depth_bytes ( u32 format )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV422 :
return 4 ;
case I915_OVERLAY_YUV411 :
/* return 6; not implemented */
default :
return - EINVAL ;
2009-09-16 00:57:34 +04:00
}
}
static int packed_width_bytes ( u32 format , short width )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV422 :
return width < < 1 ;
default :
return - EINVAL ;
2009-09-16 00:57:34 +04:00
}
}
static int uv_hsubsampling ( u32 format )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV422 :
case I915_OVERLAY_YUV420 :
return 2 ;
case I915_OVERLAY_YUV411 :
case I915_OVERLAY_YUV410 :
return 4 ;
default :
return - EINVAL ;
2009-09-16 00:57:34 +04:00
}
}
static int uv_vsubsampling ( u32 format )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV420 :
case I915_OVERLAY_YUV410 :
return 2 ;
case I915_OVERLAY_YUV422 :
case I915_OVERLAY_YUV411 :
return 1 ;
default :
return - EINVAL ;
2009-09-16 00:57:34 +04:00
}
}
static u32 calc_swidthsw ( struct drm_device * dev , u32 offset , u32 width )
{
u32 mask , shift , ret ;
2010-09-17 03:32:17 +04:00
if ( IS_GEN2 ( dev ) ) {
2009-09-16 00:57:34 +04:00
mask = 0x1f ;
shift = 5 ;
2010-09-17 03:32:17 +04:00
} else {
mask = 0x3f ;
shift = 6 ;
2009-09-16 00:57:34 +04:00
}
ret = ( ( offset + width + mask ) > > shift ) - ( offset > > shift ) ;
2010-09-17 03:32:17 +04:00
if ( ! IS_GEN2 ( dev ) )
2009-09-16 00:57:34 +04:00
ret < < = 1 ;
2011-08-16 23:34:10 +04:00
ret - = 1 ;
2009-09-16 00:57:34 +04:00
return ret < < 2 ;
}
static const u16 y_static_hcoeffs [ N_HORIZ_Y_TAPS * N_PHASES ] = {
0x3000 , 0xb4a0 , 0x1930 , 0x1920 , 0xb4a0 ,
0x3000 , 0xb500 , 0x19d0 , 0x1880 , 0xb440 ,
0x3000 , 0xb540 , 0x1a88 , 0x2f80 , 0xb3e0 ,
0x3000 , 0xb580 , 0x1b30 , 0x2e20 , 0xb380 ,
0x3000 , 0xb5c0 , 0x1bd8 , 0x2cc0 , 0xb320 ,
0x3020 , 0xb5e0 , 0x1c60 , 0x2b80 , 0xb2c0 ,
0x3020 , 0xb5e0 , 0x1cf8 , 0x2a20 , 0xb260 ,
0x3020 , 0xb5e0 , 0x1d80 , 0x28e0 , 0xb200 ,
0x3020 , 0xb5c0 , 0x1e08 , 0x3f40 , 0xb1c0 ,
0x3020 , 0xb580 , 0x1e78 , 0x3ce0 , 0xb160 ,
0x3040 , 0xb520 , 0x1ed8 , 0x3aa0 , 0xb120 ,
0x3040 , 0xb4a0 , 0x1f30 , 0x3880 , 0xb0e0 ,
0x3040 , 0xb400 , 0x1f78 , 0x3680 , 0xb0a0 ,
0x3020 , 0xb340 , 0x1fb8 , 0x34a0 , 0xb060 ,
0x3020 , 0xb240 , 0x1fe0 , 0x32e0 , 0xb040 ,
0x3020 , 0xb140 , 0x1ff8 , 0x3160 , 0xb020 ,
2010-08-12 12:28:50 +04:00
0xb000 , 0x3000 , 0x0800 , 0x3000 , 0xb000
} ;
2009-09-16 00:57:34 +04:00
static const u16 uv_static_hcoeffs [ N_HORIZ_UV_TAPS * N_PHASES ] = {
0x3000 , 0x1800 , 0x1800 , 0xb000 , 0x18d0 , 0x2e60 ,
0xb000 , 0x1990 , 0x2ce0 , 0xb020 , 0x1a68 , 0x2b40 ,
0xb040 , 0x1b20 , 0x29e0 , 0xb060 , 0x1bd8 , 0x2880 ,
0xb080 , 0x1c88 , 0x3e60 , 0xb0a0 , 0x1d28 , 0x3c00 ,
0xb0c0 , 0x1db8 , 0x39e0 , 0xb0e0 , 0x1e40 , 0x37e0 ,
0xb100 , 0x1eb8 , 0x3620 , 0xb100 , 0x1f18 , 0x34a0 ,
0xb100 , 0x1f68 , 0x3360 , 0xb0e0 , 0x1fa8 , 0x3240 ,
0xb0c0 , 0x1fe0 , 0x3140 , 0xb060 , 0x1ff0 , 0x30a0 ,
2010-08-12 12:28:50 +04:00
0x3000 , 0x0800 , 0x3000
} ;
2009-09-16 00:57:34 +04:00
2012-04-17 01:07:43 +04:00
static void update_polyphase_filter ( struct overlay_registers __iomem * regs )
2009-09-16 00:57:34 +04:00
{
2012-04-17 01:07:43 +04:00
memcpy_toio ( regs - > Y_HCOEFS , y_static_hcoeffs , sizeof ( y_static_hcoeffs ) ) ;
memcpy_toio ( regs - > UV_HCOEFS , uv_static_hcoeffs ,
sizeof ( uv_static_hcoeffs ) ) ;
2009-09-16 00:57:34 +04:00
}
static bool update_scaling_factors ( struct intel_overlay * overlay ,
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ,
2009-09-16 00:57:34 +04:00
struct put_image_params * params )
{
/* fixed point with a 12 bit shift */
u32 xscale , yscale , xscale_UV , yscale_UV ;
# define FP_SHIFT 12
# define FRACT_MASK 0xfff
bool scale_changed = false ;
int uv_hscale = uv_hsubsampling ( params - > format ) ;
int uv_vscale = uv_vsubsampling ( params - > format ) ;
if ( params - > dst_w > 1 )
xscale = ( ( params - > src_scan_w - 1 ) < < FP_SHIFT )
/ ( params - > dst_w ) ;
else
xscale = 1 < < FP_SHIFT ;
if ( params - > dst_h > 1 )
yscale = ( ( params - > src_scan_h - 1 ) < < FP_SHIFT )
/ ( params - > dst_h ) ;
else
yscale = 1 < < FP_SHIFT ;
/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
2010-08-12 12:28:50 +04:00
xscale_UV = xscale / uv_hscale ;
yscale_UV = yscale / uv_vscale ;
/* make the Y scale to UV scale ratio an exact multiply */
xscale = xscale_UV * uv_hscale ;
yscale = yscale_UV * uv_vscale ;
2009-09-16 00:57:34 +04:00
/*} else {
2010-08-12 12:28:50 +04:00
xscale_UV = 0 ;
yscale_UV = 0 ;
} */
2009-09-16 00:57:34 +04:00
if ( xscale ! = overlay - > old_xscale | | yscale ! = overlay - > old_yscale )
scale_changed = true ;
overlay - > old_xscale = xscale ;
overlay - > old_yscale = yscale ;
2012-04-17 01:07:43 +04:00
iowrite32 ( ( ( yscale & FRACT_MASK ) < < 20 ) |
( ( xscale > > FP_SHIFT ) < < 16 ) |
( ( xscale & FRACT_MASK ) < < 3 ) ,
& regs - > YRGBSCALE ) ;
2010-08-12 12:28:50 +04:00
2012-04-17 01:07:43 +04:00
iowrite32 ( ( ( yscale_UV & FRACT_MASK ) < < 20 ) |
( ( xscale_UV > > FP_SHIFT ) < < 16 ) |
( ( xscale_UV & FRACT_MASK ) < < 3 ) ,
& regs - > UVSCALE ) ;
2010-08-12 12:28:50 +04:00
2012-04-17 01:07:43 +04:00
iowrite32 ( ( ( ( yscale > > FP_SHIFT ) < < 16 ) |
( ( yscale_UV > > FP_SHIFT ) < < 0 ) ) ,
& regs - > UVSCALEV ) ;
2009-09-16 00:57:34 +04:00
if ( scale_changed )
update_polyphase_filter ( regs ) ;
return scale_changed ;
}
static void update_colorkey ( struct intel_overlay * overlay ,
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs )
2009-09-16 00:57:34 +04:00
{
u32 key = overlay - > color_key ;
2010-08-12 12:30:58 +04:00
2009-09-16 00:57:34 +04:00
switch ( overlay - > crtc - > base . fb - > bits_per_pixel ) {
2010-08-12 12:28:50 +04:00
case 8 :
2012-04-17 01:07:43 +04:00
iowrite32 ( 0 , & regs - > DCLRKV ) ;
iowrite32 ( CLK_RGB8I_MASK | DST_KEY_ENABLE , & regs - > DCLRKM ) ;
2010-08-12 12:30:58 +04:00
break ;
2010-08-12 12:28:50 +04:00
case 16 :
if ( overlay - > crtc - > base . fb - > depth = = 15 ) {
2012-04-17 01:07:43 +04:00
iowrite32 ( RGB15_TO_COLORKEY ( key ) , & regs - > DCLRKV ) ;
iowrite32 ( CLK_RGB15_MASK | DST_KEY_ENABLE ,
& regs - > DCLRKM ) ;
2010-08-12 12:28:50 +04:00
} else {
2012-04-17 01:07:43 +04:00
iowrite32 ( RGB16_TO_COLORKEY ( key ) , & regs - > DCLRKV ) ;
iowrite32 ( CLK_RGB16_MASK | DST_KEY_ENABLE ,
& regs - > DCLRKM ) ;
2010-08-12 12:28:50 +04:00
}
2010-08-12 12:30:58 +04:00
break ;
2010-08-12 12:28:50 +04:00
case 24 :
case 32 :
2012-04-17 01:07:43 +04:00
iowrite32 ( key , & regs - > DCLRKV ) ;
iowrite32 ( CLK_RGB24_MASK | DST_KEY_ENABLE , & regs - > DCLRKM ) ;
2010-08-12 12:30:58 +04:00
break ;
2009-09-16 00:57:34 +04:00
}
}
static u32 overlay_cmd_reg ( struct put_image_params * params )
{
u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0 ;
if ( params - > format & I915_OVERLAY_YUV_PLANAR ) {
switch ( params - > format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV422 :
cmd | = OCMD_YUV_422_PLANAR ;
break ;
case I915_OVERLAY_YUV420 :
cmd | = OCMD_YUV_420_PLANAR ;
break ;
case I915_OVERLAY_YUV411 :
case I915_OVERLAY_YUV410 :
cmd | = OCMD_YUV_410_PLANAR ;
break ;
2009-09-16 00:57:34 +04:00
}
} else { /* YUV packed */
switch ( params - > format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV422 :
cmd | = OCMD_YUV_422_PACKED ;
break ;
case I915_OVERLAY_YUV411 :
cmd | = OCMD_YUV_411_PACKED ;
break ;
2009-09-16 00:57:34 +04:00
}
switch ( params - > format & I915_OVERLAY_SWAP_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_NO_SWAP :
break ;
case I915_OVERLAY_UV_SWAP :
cmd | = OCMD_UV_SWAP ;
break ;
case I915_OVERLAY_Y_SWAP :
cmd | = OCMD_Y_SWAP ;
break ;
case I915_OVERLAY_Y_AND_UV_SWAP :
cmd | = OCMD_Y_AND_UV_SWAP ;
break ;
2009-09-16 00:57:34 +04:00
}
}
return cmd ;
}
2010-08-12 15:38:21 +04:00
static int intel_overlay_do_put_image ( struct intel_overlay * overlay ,
2010-11-08 22:18:58 +03:00
struct drm_i915_gem_object * new_bo ,
2010-08-12 15:38:21 +04:00
struct put_image_params * params )
2009-09-16 00:57:34 +04:00
{
int ret , tmp_width ;
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ;
2009-09-16 00:57:34 +04:00
bool scale_changed = false ;
struct drm_device * dev = overlay - > dev ;
2012-04-17 01:07:43 +04:00
u32 swidth , swidthsw , sheight , ostride ;
2009-09-16 00:57:34 +04:00
BUG_ON ( ! mutex_is_locked ( & dev - > struct_mutex ) ) ;
BUG_ON ( ! mutex_is_locked ( & dev - > mode_config . mutex ) ) ;
BUG_ON ( ! overlay ) ;
ret = intel_overlay_release_old_vid ( overlay ) ;
if ( ret ! = 0 )
return ret ;
2011-04-14 12:41:17 +04:00
ret = i915_gem_object_pin_to_display_plane ( new_bo , 0 , NULL ) ;
2009-09-16 00:57:34 +04:00
if ( ret ! = 0 )
return ret ;
2010-11-10 19:40:20 +03:00
ret = i915_gem_object_put_fence ( new_bo ) ;
if ( ret )
goto out_unpin ;
2009-09-16 00:57:34 +04:00
if ( ! overlay - > active ) {
2012-04-17 01:07:43 +04:00
u32 oconfig ;
2010-08-12 13:35:26 +04:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-16 00:57:34 +04:00
if ( ! regs ) {
ret = - ENOMEM ;
goto out_unpin ;
}
2012-04-17 01:07:43 +04:00
oconfig = OCONF_CC_OUT_8BIT ;
2010-09-17 03:32:17 +04:00
if ( IS_GEN4 ( overlay - > dev ) )
2012-04-17 01:07:43 +04:00
oconfig | = OCONF_CSC_MODE_BT709 ;
oconfig | = overlay - > crtc - > pipe = = 0 ?
2009-09-16 00:57:34 +04:00
OCONF_PIPE_A : OCONF_PIPE_B ;
2012-04-17 01:07:43 +04:00
iowrite32 ( oconfig , & regs - > OCONFIG ) ;
2010-08-12 15:02:11 +04:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-16 00:57:34 +04:00
ret = intel_overlay_on ( overlay ) ;
if ( ret ! = 0 )
goto out_unpin ;
}
2010-08-12 13:35:26 +04:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-16 00:57:34 +04:00
if ( ! regs ) {
ret = - ENOMEM ;
goto out_unpin ;
}
2012-04-17 01:07:43 +04:00
iowrite32 ( ( params - > dst_y < < 16 ) | params - > dst_x , & regs - > DWINPOS ) ;
iowrite32 ( ( params - > dst_h < < 16 ) | params - > dst_w , & regs - > DWINSZ ) ;
2009-09-16 00:57:34 +04:00
if ( params - > format & I915_OVERLAY_YUV_PACKED )
tmp_width = packed_width_bytes ( params - > format , params - > src_w ) ;
else
tmp_width = params - > src_w ;
2012-04-17 01:07:43 +04:00
swidth = params - > src_w ;
swidthsw = calc_swidthsw ( overlay - > dev , params - > offset_Y , tmp_width ) ;
sheight = params - > src_h ;
iowrite32 ( new_bo - > gtt_offset + params - > offset_Y , & regs - > OBUF_0Y ) ;
ostride = params - > stride_Y ;
2009-09-16 00:57:34 +04:00
if ( params - > format & I915_OVERLAY_YUV_PLANAR ) {
int uv_hscale = uv_hsubsampling ( params - > format ) ;
int uv_vscale = uv_vsubsampling ( params - > format ) ;
u32 tmp_U , tmp_V ;
2012-04-17 01:07:43 +04:00
swidth | = ( params - > src_w / uv_hscale ) < < 16 ;
2009-09-16 00:57:34 +04:00
tmp_U = calc_swidthsw ( overlay - > dev , params - > offset_U ,
2010-08-12 12:28:50 +04:00
params - > src_w / uv_hscale ) ;
2009-09-16 00:57:34 +04:00
tmp_V = calc_swidthsw ( overlay - > dev , params - > offset_V ,
2010-08-12 12:28:50 +04:00
params - > src_w / uv_hscale ) ;
2012-04-17 01:07:43 +04:00
swidthsw | = max_t ( u32 , tmp_U , tmp_V ) < < 16 ;
sheight | = ( params - > src_h / uv_vscale ) < < 16 ;
iowrite32 ( new_bo - > gtt_offset + params - > offset_U , & regs - > OBUF_0U ) ;
iowrite32 ( new_bo - > gtt_offset + params - > offset_V , & regs - > OBUF_0V ) ;
ostride | = params - > stride_UV < < 16 ;
2009-09-16 00:57:34 +04:00
}
2012-04-17 01:07:43 +04:00
iowrite32 ( swidth , & regs - > SWIDTH ) ;
iowrite32 ( swidthsw , & regs - > SWIDTHSW ) ;
iowrite32 ( sheight , & regs - > SHEIGHT ) ;
iowrite32 ( ostride , & regs - > OSTRIDE ) ;
2009-09-16 00:57:34 +04:00
scale_changed = update_scaling_factors ( overlay , regs , params ) ;
update_colorkey ( overlay , regs ) ;
2012-04-17 01:07:43 +04:00
iowrite32 ( overlay_cmd_reg ( params ) , & regs - > OCMD ) ;
2009-09-16 00:57:34 +04:00
2010-08-12 15:02:11 +04:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-16 00:57:34 +04:00
2010-08-12 15:36:12 +04:00
ret = intel_overlay_continue ( overlay , scale_changed ) ;
if ( ret )
goto out_unpin ;
2009-09-16 00:57:34 +04:00
overlay - > old_vid_bo = overlay - > vid_bo ;
2010-11-08 22:18:58 +03:00
overlay - > vid_bo = new_bo ;
2009-09-16 00:57:34 +04:00
return 0 ;
out_unpin :
i915_gem_object_unpin ( new_bo ) ;
return ret ;
}
2011-02-21 17:43:56 +03:00
int intel_overlay_switch_off ( struct intel_overlay * overlay )
2009-09-16 00:57:34 +04:00
{
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ;
2009-09-16 00:57:34 +04:00
struct drm_device * dev = overlay - > dev ;
2010-08-12 16:50:28 +04:00
int ret ;
2009-09-16 00:57:34 +04:00
BUG_ON ( ! mutex_is_locked ( & dev - > struct_mutex ) ) ;
BUG_ON ( ! mutex_is_locked ( & dev - > mode_config . mutex ) ) ;
2011-02-21 17:43:56 +03:00
ret = intel_overlay_recover_from_interrupt ( overlay ) ;
2010-08-12 17:03:48 +04:00
if ( ret ! = 0 )
return ret ;
2009-11-30 17:55:49 +03:00
2009-09-16 00:57:34 +04:00
if ( ! overlay - > active )
return 0 ;
ret = intel_overlay_release_old_vid ( overlay ) ;
if ( ret ! = 0 )
return ret ;
2010-08-12 13:35:26 +04:00
regs = intel_overlay_map_regs ( overlay ) ;
2012-04-17 01:07:43 +04:00
iowrite32 ( 0 , & regs - > OCMD ) ;
2010-08-12 15:02:11 +04:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-16 00:57:34 +04:00
2011-02-21 17:43:56 +03:00
ret = intel_overlay_off ( overlay ) ;
2009-09-16 00:57:37 +04:00
if ( ret ! = 0 )
return ret ;
2037-04-25 11:08:26 +03:00
intel_overlay_off_tail ( overlay ) ;
2009-09-16 00:57:34 +04:00
return 0 ;
}
static int check_overlay_possible_on_crtc ( struct intel_overlay * overlay ,
struct intel_crtc * crtc )
{
2010-08-12 12:28:50 +04:00
drm_i915_private_t * dev_priv = overlay - > dev - > dev_private ;
2009-09-16 00:57:34 +04:00
2010-09-13 17:19:16 +04:00
if ( ! crtc - > active )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
/* can't use the overlay with double wide pipe */
2010-09-17 03:32:17 +04:00
if ( INTEL_INFO ( overlay - > dev ) - > gen < 4 & &
2010-09-13 17:19:16 +04:00
( I915_READ ( PIPECONF ( crtc - > pipe ) ) & ( PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE ) ) ! = PIPECONF_ENABLE )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
return 0 ;
}
static void update_pfit_vscale_ratio ( struct intel_overlay * overlay )
{
struct drm_device * dev = overlay - > dev ;
2010-08-12 12:28:50 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2009-09-16 00:57:34 +04:00
u32 pfit_control = I915_READ ( PFIT_CONTROL ) ;
2010-08-12 14:15:58 +04:00
u32 ratio ;
2009-09-16 00:57:34 +04:00
/* XXX: This is not the same logic as in the xorg driver, but more in
2010-08-12 14:15:58 +04:00
* line with the intel documentation for the i965
*/
2010-09-17 03:32:17 +04:00
if ( INTEL_INFO ( dev ) - > gen > = 4 ) {
2011-08-16 23:34:10 +04:00
/* on i965 use the PGM reg to read out the autoscaler values */
2010-09-17 03:32:17 +04:00
ratio = I915_READ ( PFIT_PGM_RATIOS ) > > PFIT_VERT_SCALE_SHIFT_965 ;
} else {
2010-08-12 14:15:58 +04:00
if ( pfit_control & VERT_AUTO_SCALE )
ratio = I915_READ ( PFIT_AUTO_RATIOS ) ;
2009-09-16 00:57:34 +04:00
else
2010-08-12 14:15:58 +04:00
ratio = I915_READ ( PFIT_PGM_RATIOS ) ;
ratio > > = PFIT_VERT_SCALE_SHIFT ;
2009-09-16 00:57:34 +04:00
}
overlay - > pfit_vscale_ratio = ratio ;
}
static int check_overlay_dst ( struct intel_overlay * overlay ,
struct drm_intel_overlay_put_image * rec )
{
struct drm_display_mode * mode = & overlay - > crtc - > base . mode ;
2012-01-29 02:48:46 +04:00
if ( rec - > dst_x < mode - > hdisplay & &
rec - > dst_x + rec - > dst_width < = mode - > hdisplay & &
rec - > dst_y < mode - > vdisplay & &
rec - > dst_y + rec - > dst_height < = mode - > vdisplay )
2009-09-16 00:57:34 +04:00
return 0 ;
else
return - EINVAL ;
}
static int check_overlay_scaling ( struct put_image_params * rec )
{
u32 tmp ;
/* downscaling limit is 8.0 */
tmp = ( ( rec - > src_scan_h < < 16 ) / rec - > dst_h ) > > 16 ;
if ( tmp > 7 )
return - EINVAL ;
tmp = ( ( rec - > src_scan_w < < 16 ) / rec - > dst_w ) > > 16 ;
if ( tmp > 7 )
return - EINVAL ;
return 0 ;
}
static int check_overlay_src ( struct drm_device * dev ,
struct drm_intel_overlay_put_image * rec ,
2010-11-08 22:18:58 +03:00
struct drm_i915_gem_object * new_bo )
2009-09-16 00:57:34 +04:00
{
int uv_hscale = uv_hsubsampling ( rec - > flags ) ;
int uv_vscale = uv_vsubsampling ( rec - > flags ) ;
2010-10-28 01:17:25 +04:00
u32 stride_mask ;
int depth ;
u32 tmp ;
2009-09-16 00:57:34 +04:00
/* check src dimensions */
if ( IS_845G ( dev ) | | IS_I830 ( dev ) ) {
2010-08-12 12:28:50 +04:00
if ( rec - > src_height > IMAGE_MAX_HEIGHT_LEGACY | |
2010-08-12 14:29:34 +04:00
rec - > src_width > IMAGE_MAX_WIDTH_LEGACY )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
} else {
2010-08-12 12:28:50 +04:00
if ( rec - > src_height > IMAGE_MAX_HEIGHT | |
2010-08-12 14:29:34 +04:00
rec - > src_width > IMAGE_MAX_WIDTH )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
}
2010-08-12 14:29:34 +04:00
2009-09-16 00:57:34 +04:00
/* better safe than sorry, use 4 as the maximal subsampling ratio */
2010-08-12 12:28:50 +04:00
if ( rec - > src_height < N_VERT_Y_TAPS * 4 | |
2010-08-12 14:29:34 +04:00
rec - > src_width < N_HORIZ_Y_TAPS * 4 )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
2010-07-12 22:35:38 +04:00
/* check alignment constraints */
2009-09-16 00:57:34 +04:00
switch ( rec - > flags & I915_OVERLAY_TYPE_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_RGB :
/* not implemented */
return - EINVAL ;
2010-08-12 14:29:34 +04:00
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV_PACKED :
if ( uv_vscale ! = 1 )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
2010-08-12 14:29:34 +04:00
depth = packed_depth_bytes ( rec - > flags ) ;
2010-08-12 12:28:50 +04:00
if ( depth < 0 )
return depth ;
2010-08-12 14:29:34 +04:00
2010-08-12 12:28:50 +04:00
/* ignore UV planes */
rec - > stride_UV = 0 ;
rec - > offset_U = 0 ;
rec - > offset_V = 0 ;
/* check pixel alignment */
if ( rec - > offset_Y % depth )
return - EINVAL ;
break ;
2010-08-12 14:29:34 +04:00
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_YUV_PLANAR :
if ( uv_vscale < 0 | | uv_hscale < 0 )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
2010-08-12 12:28:50 +04:00
/* no offset restrictions for planar formats */
break ;
2010-08-12 14:29:34 +04:00
2010-08-12 12:28:50 +04:00
default :
return - EINVAL ;
2009-09-16 00:57:34 +04:00
}
if ( rec - > src_width % uv_hscale )
return - EINVAL ;
/* stride checking */
2010-07-12 22:35:38 +04:00
if ( IS_I830 ( dev ) | | IS_845G ( dev ) )
stride_mask = 255 ;
else
stride_mask = 63 ;
2009-09-16 00:57:34 +04:00
if ( rec - > stride_Y & stride_mask | | rec - > stride_UV & stride_mask )
return - EINVAL ;
2010-09-17 03:32:17 +04:00
if ( IS_GEN4 ( dev ) & & rec - > stride_Y < 512 )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
tmp = ( rec - > flags & I915_OVERLAY_TYPE_MASK ) = = I915_OVERLAY_YUV_PLANAR ?
2010-08-12 14:29:34 +04:00
4096 : 8192 ;
if ( rec - > stride_Y > tmp | | rec - > stride_UV > 2 * 1024 )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
/* check buffer dimensions */
switch ( rec - > flags & I915_OVERLAY_TYPE_MASK ) {
2010-08-12 12:28:50 +04:00
case I915_OVERLAY_RGB :
case I915_OVERLAY_YUV_PACKED :
/* always 4 Y values per depth pixels */
if ( packed_width_bytes ( rec - > flags , rec - > src_width ) > rec - > stride_Y )
return - EINVAL ;
tmp = rec - > stride_Y * rec - > src_height ;
2010-11-08 22:18:58 +03:00
if ( rec - > offset_Y + tmp > new_bo - > base . size )
2010-08-12 12:28:50 +04:00
return - EINVAL ;
break ;
case I915_OVERLAY_YUV_PLANAR :
if ( rec - > src_width > rec - > stride_Y )
return - EINVAL ;
if ( rec - > src_width / uv_hscale > rec - > stride_UV )
return - EINVAL ;
2010-08-12 14:29:34 +04:00
tmp = rec - > stride_Y * rec - > src_height ;
2010-11-08 22:18:58 +03:00
if ( rec - > offset_Y + tmp > new_bo - > base . size )
2010-08-12 12:28:50 +04:00
return - EINVAL ;
2010-08-12 14:29:34 +04:00
tmp = rec - > stride_UV * ( rec - > src_height / uv_vscale ) ;
2010-11-08 22:18:58 +03:00
if ( rec - > offset_U + tmp > new_bo - > base . size | |
rec - > offset_V + tmp > new_bo - > base . size )
2010-08-12 12:28:50 +04:00
return - EINVAL ;
break ;
2009-09-16 00:57:34 +04:00
}
return 0 ;
}
2010-09-13 04:16:10 +04:00
/**
* Return the pipe currently connected to the panel fitter ,
* or - 1 if the panel fitter is not present or not in use
*/
static int intel_panel_fitter_pipe ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
u32 pfit_control ;
/* i830 doesn't have a panel fitter */
if ( IS_I830 ( dev ) )
return - 1 ;
pfit_control = I915_READ ( PFIT_CONTROL ) ;
/* See if the panel fitter is in use */
if ( ( pfit_control & PFIT_ENABLE ) = = 0 )
return - 1 ;
/* 965 can place panel fitter on either pipe */
2010-09-17 03:32:17 +04:00
if ( IS_GEN4 ( dev ) )
2010-09-13 04:16:10 +04:00
return ( pfit_control > > 29 ) & 0x3 ;
/* older chips can only use pipe 1 */
return 1 ;
}
2009-09-16 00:57:34 +04:00
int intel_overlay_put_image ( struct drm_device * dev , void * data ,
2011-08-16 23:34:10 +04:00
struct drm_file * file_priv )
2009-09-16 00:57:34 +04:00
{
struct drm_intel_overlay_put_image * put_image_rec = data ;
drm_i915_private_t * dev_priv = dev - > dev_private ;
struct intel_overlay * overlay ;
struct drm_mode_object * drmmode_obj ;
struct intel_crtc * crtc ;
2010-11-08 22:18:58 +03:00
struct drm_i915_gem_object * new_bo ;
2009-09-16 00:57:34 +04:00
struct put_image_params * params ;
int ret ;
if ( ! dev_priv ) {
DRM_ERROR ( " called with no initialization \n " ) ;
return - EINVAL ;
}
overlay = dev_priv - > overlay ;
if ( ! overlay ) {
DRM_DEBUG ( " userspace bug: no overlay \n " ) ;
return - ENODEV ;
}
if ( ! ( put_image_rec - > flags & I915_OVERLAY_ENABLE ) ) {
mutex_lock ( & dev - > mode_config . mutex ) ;
mutex_lock ( & dev - > struct_mutex ) ;
2011-02-21 17:43:56 +03:00
ret = intel_overlay_switch_off ( overlay ) ;
2009-09-16 00:57:34 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
mutex_unlock ( & dev - > mode_config . mutex ) ;
return ret ;
}
params = kmalloc ( sizeof ( struct put_image_params ) , GFP_KERNEL ) ;
if ( ! params )
return - ENOMEM ;
drmmode_obj = drm_mode_object_find ( dev , put_image_rec - > crtc_id ,
2010-08-12 12:28:50 +04:00
DRM_MODE_OBJECT_CRTC ) ;
2010-03-06 14:05:39 +03:00
if ( ! drmmode_obj ) {
ret = - ENOENT ;
goto out_free ;
}
2009-09-16 00:57:34 +04:00
crtc = to_intel_crtc ( obj_to_crtc ( drmmode_obj ) ) ;
2010-11-08 22:18:58 +03:00
new_bo = to_intel_bo ( drm_gem_object_lookup ( dev , file_priv ,
put_image_rec - > bo_handle ) ) ;
2011-02-19 14:31:06 +03:00
if ( & new_bo - > base = = NULL ) {
2010-03-06 14:05:39 +03:00
ret = - ENOENT ;
goto out_free ;
}
2009-09-16 00:57:34 +04:00
mutex_lock ( & dev - > mode_config . mutex ) ;
mutex_lock ( & dev - > struct_mutex ) ;
2010-11-10 19:40:20 +03:00
if ( new_bo - > tiling_mode ) {
DRM_ERROR ( " buffer used for overlay image can not be tiled \n " ) ;
ret = - EINVAL ;
goto out_unlock ;
}
2011-02-21 17:43:56 +03:00
ret = intel_overlay_recover_from_interrupt ( overlay ) ;
2010-08-12 17:03:48 +04:00
if ( ret ! = 0 )
goto out_unlock ;
2009-09-16 00:57:37 +04:00
2009-09-16 00:57:34 +04:00
if ( overlay - > crtc ! = crtc ) {
struct drm_display_mode * mode = & crtc - > base . mode ;
2011-02-21 17:43:56 +03:00
ret = intel_overlay_switch_off ( overlay ) ;
2009-09-16 00:57:34 +04:00
if ( ret ! = 0 )
goto out_unlock ;
ret = check_overlay_possible_on_crtc ( overlay , crtc ) ;
if ( ret ! = 0 )
goto out_unlock ;
overlay - > crtc = crtc ;
crtc - > overlay = overlay ;
2010-09-13 04:16:10 +04:00
/* line too wide, i.e. one-line-mode */
if ( mode - > hdisplay > 1024 & &
intel_panel_fitter_pipe ( dev ) = = crtc - > pipe ) {
2009-09-16 00:57:34 +04:00
overlay - > pfit_active = 1 ;
update_pfit_vscale_ratio ( overlay ) ;
} else
overlay - > pfit_active = 0 ;
}
ret = check_overlay_dst ( overlay , put_image_rec ) ;
if ( ret ! = 0 )
goto out_unlock ;
if ( overlay - > pfit_active ) {
params - > dst_y = ( ( ( ( u32 ) put_image_rec - > dst_y ) < < 12 ) /
2010-08-12 12:28:50 +04:00
overlay - > pfit_vscale_ratio ) ;
2009-09-16 00:57:34 +04:00
/* shifting right rounds downwards, so add 1 */
params - > dst_h = ( ( ( ( u32 ) put_image_rec - > dst_height ) < < 12 ) /
2010-08-12 12:28:50 +04:00
overlay - > pfit_vscale_ratio ) + 1 ;
2009-09-16 00:57:34 +04:00
} else {
params - > dst_y = put_image_rec - > dst_y ;
params - > dst_h = put_image_rec - > dst_height ;
}
params - > dst_x = put_image_rec - > dst_x ;
params - > dst_w = put_image_rec - > dst_width ;
params - > src_w = put_image_rec - > src_width ;
params - > src_h = put_image_rec - > src_height ;
params - > src_scan_w = put_image_rec - > src_scan_width ;
params - > src_scan_h = put_image_rec - > src_scan_height ;
2010-08-12 12:28:50 +04:00
if ( params - > src_scan_h > params - > src_h | |
params - > src_scan_w > params - > src_w ) {
2009-09-16 00:57:34 +04:00
ret = - EINVAL ;
goto out_unlock ;
}
ret = check_overlay_src ( dev , put_image_rec , new_bo ) ;
if ( ret ! = 0 )
goto out_unlock ;
params - > format = put_image_rec - > flags & ~ I915_OVERLAY_FLAGS_MASK ;
params - > stride_Y = put_image_rec - > stride_Y ;
params - > stride_UV = put_image_rec - > stride_UV ;
params - > offset_Y = put_image_rec - > offset_Y ;
params - > offset_U = put_image_rec - > offset_U ;
params - > offset_V = put_image_rec - > offset_V ;
/* Check scaling after src size to prevent a divide-by-zero. */
ret = check_overlay_scaling ( params ) ;
if ( ret ! = 0 )
goto out_unlock ;
ret = intel_overlay_do_put_image ( overlay , new_bo , params ) ;
if ( ret ! = 0 )
goto out_unlock ;
mutex_unlock ( & dev - > struct_mutex ) ;
mutex_unlock ( & dev - > mode_config . mutex ) ;
kfree ( params ) ;
return 0 ;
out_unlock :
mutex_unlock ( & dev - > struct_mutex ) ;
mutex_unlock ( & dev - > mode_config . mutex ) ;
2010-11-08 22:18:58 +03:00
drm_gem_object_unreference_unlocked ( & new_bo - > base ) ;
2010-03-06 14:05:39 +03:00
out_free :
2009-09-16 00:57:34 +04:00
kfree ( params ) ;
return ret ;
}
static void update_reg_attrs ( struct intel_overlay * overlay ,
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs )
2009-09-16 00:57:34 +04:00
{
2012-04-17 01:07:43 +04:00
iowrite32 ( ( overlay - > contrast < < 18 ) | ( overlay - > brightness & 0xff ) ,
& regs - > OCLRC0 ) ;
iowrite32 ( overlay - > saturation , & regs - > OCLRC1 ) ;
2009-09-16 00:57:34 +04:00
}
static bool check_gamma_bounds ( u32 gamma1 , u32 gamma2 )
{
int i ;
if ( gamma1 & 0xff000000 | | gamma2 & 0xff000000 )
return false ;
for ( i = 0 ; i < 3 ; i + + ) {
2010-08-12 12:28:50 +04:00
if ( ( ( gamma1 > > i * 8 ) & 0xff ) > = ( ( gamma2 > > i * 8 ) & 0xff ) )
2009-09-16 00:57:34 +04:00
return false ;
}
return true ;
}
static bool check_gamma5_errata ( u32 gamma5 )
{
int i ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( ( ( gamma5 > > i * 8 ) & 0xff ) = = 0x80 )
return false ;
}
return true ;
}
static int check_gamma ( struct drm_intel_overlay_attrs * attrs )
{
2010-08-12 12:28:50 +04:00
if ( ! check_gamma_bounds ( 0 , attrs - > gamma0 ) | |
! check_gamma_bounds ( attrs - > gamma0 , attrs - > gamma1 ) | |
! check_gamma_bounds ( attrs - > gamma1 , attrs - > gamma2 ) | |
! check_gamma_bounds ( attrs - > gamma2 , attrs - > gamma3 ) | |
! check_gamma_bounds ( attrs - > gamma3 , attrs - > gamma4 ) | |
! check_gamma_bounds ( attrs - > gamma4 , attrs - > gamma5 ) | |
! check_gamma_bounds ( attrs - > gamma5 , 0x00ffffff ) )
2009-09-16 00:57:34 +04:00
return - EINVAL ;
2010-08-12 12:28:50 +04:00
2009-09-16 00:57:34 +04:00
if ( ! check_gamma5_errata ( attrs - > gamma5 ) )
return - EINVAL ;
2010-08-12 12:28:50 +04:00
2009-09-16 00:57:34 +04:00
return 0 ;
}
int intel_overlay_attrs ( struct drm_device * dev , void * data ,
2011-08-16 23:34:10 +04:00
struct drm_file * file_priv )
2009-09-16 00:57:34 +04:00
{
struct drm_intel_overlay_attrs * attrs = data ;
2011-08-16 23:34:10 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2009-09-16 00:57:34 +04:00
struct intel_overlay * overlay ;
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ;
2009-09-16 00:57:34 +04:00
int ret ;
if ( ! dev_priv ) {
DRM_ERROR ( " called with no initialization \n " ) ;
return - EINVAL ;
}
overlay = dev_priv - > overlay ;
if ( ! overlay ) {
DRM_DEBUG ( " userspace bug: no overlay \n " ) ;
return - ENODEV ;
}
mutex_lock ( & dev - > mode_config . mutex ) ;
mutex_lock ( & dev - > struct_mutex ) ;
2010-08-12 13:44:45 +04:00
ret = - EINVAL ;
2009-09-16 00:57:34 +04:00
if ( ! ( attrs - > flags & I915_OVERLAY_UPDATE_ATTRS ) ) {
2010-08-12 13:44:45 +04:00
attrs - > color_key = overlay - > color_key ;
2009-09-16 00:57:34 +04:00
attrs - > brightness = overlay - > brightness ;
2010-08-12 13:44:45 +04:00
attrs - > contrast = overlay - > contrast ;
2009-09-16 00:57:34 +04:00
attrs - > saturation = overlay - > saturation ;
2010-09-17 03:32:17 +04:00
if ( ! IS_GEN2 ( dev ) ) {
2009-09-16 00:57:34 +04:00
attrs - > gamma0 = I915_READ ( OGAMC0 ) ;
attrs - > gamma1 = I915_READ ( OGAMC1 ) ;
attrs - > gamma2 = I915_READ ( OGAMC2 ) ;
attrs - > gamma3 = I915_READ ( OGAMC3 ) ;
attrs - > gamma4 = I915_READ ( OGAMC4 ) ;
attrs - > gamma5 = I915_READ ( OGAMC5 ) ;
}
} else {
2010-08-12 13:44:45 +04:00
if ( attrs - > brightness < - 128 | | attrs - > brightness > 127 )
2009-09-16 00:57:34 +04:00
goto out_unlock ;
2010-08-12 13:44:45 +04:00
if ( attrs - > contrast > 255 )
2009-09-16 00:57:34 +04:00
goto out_unlock ;
2010-08-12 13:44:45 +04:00
if ( attrs - > saturation > 1023 )
2009-09-16 00:57:34 +04:00
goto out_unlock ;
2010-08-12 13:44:45 +04:00
overlay - > color_key = attrs - > color_key ;
overlay - > brightness = attrs - > brightness ;
overlay - > contrast = attrs - > contrast ;
overlay - > saturation = attrs - > saturation ;
2009-09-16 00:57:34 +04:00
2010-08-12 13:35:26 +04:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-16 00:57:34 +04:00
if ( ! regs ) {
ret = - ENOMEM ;
goto out_unlock ;
}
update_reg_attrs ( overlay , regs ) ;
2010-08-12 15:02:11 +04:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-16 00:57:34 +04:00
if ( attrs - > flags & I915_OVERLAY_UPDATE_GAMMA ) {
2010-09-17 03:32:17 +04:00
if ( IS_GEN2 ( dev ) )
2009-09-16 00:57:34 +04:00
goto out_unlock ;
if ( overlay - > active ) {
ret = - EBUSY ;
goto out_unlock ;
}
ret = check_gamma ( attrs ) ;
2010-08-12 13:44:45 +04:00
if ( ret )
2009-09-16 00:57:34 +04:00
goto out_unlock ;
I915_WRITE ( OGAMC0 , attrs - > gamma0 ) ;
I915_WRITE ( OGAMC1 , attrs - > gamma1 ) ;
I915_WRITE ( OGAMC2 , attrs - > gamma2 ) ;
I915_WRITE ( OGAMC3 , attrs - > gamma3 ) ;
I915_WRITE ( OGAMC4 , attrs - > gamma4 ) ;
I915_WRITE ( OGAMC5 , attrs - > gamma5 ) ;
}
}
2010-08-12 13:44:45 +04:00
ret = 0 ;
2009-09-16 00:57:34 +04:00
out_unlock :
mutex_unlock ( & dev - > struct_mutex ) ;
mutex_unlock ( & dev - > mode_config . mutex ) ;
return ret ;
}
void intel_setup_overlay ( struct drm_device * dev )
{
2011-08-16 23:34:10 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2009-09-16 00:57:34 +04:00
struct intel_overlay * overlay ;
2010-11-08 22:18:58 +03:00
struct drm_i915_gem_object * reg_bo ;
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ;
2009-09-16 00:57:34 +04:00
int ret ;
2010-08-12 12:42:51 +04:00
if ( ! HAS_OVERLAY ( dev ) )
2009-09-16 00:57:34 +04:00
return ;
overlay = kzalloc ( sizeof ( struct intel_overlay ) , GFP_KERNEL ) ;
if ( ! overlay )
return ;
2011-06-28 14:27:47 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
if ( WARN_ON ( dev_priv - > overlay ) )
goto out_free ;
2009-09-16 00:57:34 +04:00
overlay - > dev = dev ;
2010-04-09 23:05:06 +04:00
reg_bo = i915_gem_alloc_object ( dev , PAGE_SIZE ) ;
2009-09-16 00:57:34 +04:00
if ( ! reg_bo )
goto out_free ;
2010-11-08 22:18:58 +03:00
overlay - > reg_bo = reg_bo ;
2009-09-16 00:57:34 +04:00
2010-08-12 12:42:51 +04:00
if ( OVERLAY_NEEDS_PHYSICAL ( dev ) ) {
2009-09-16 00:57:34 +04:00
ret = i915_gem_attach_phys_object ( dev , reg_bo ,
2010-08-07 14:01:39 +04:00
I915_GEM_PHYS_OVERLAY_REGS ,
2010-08-12 13:47:56 +04:00
PAGE_SIZE ) ;
2011-08-16 23:34:10 +04:00
if ( ret ) {
DRM_ERROR ( " failed to attach phys overlay regs \n " ) ;
goto out_free_bo ;
}
2010-11-08 22:18:58 +03:00
overlay - > flip_addr = reg_bo - > phys_obj - > handle - > busaddr ;
2010-08-12 12:42:51 +04:00
} else {
2010-11-04 19:11:09 +03:00
ret = i915_gem_object_pin ( reg_bo , PAGE_SIZE , true ) ;
2009-09-16 00:57:34 +04:00
if ( ret ) {
2011-08-16 23:34:10 +04:00
DRM_ERROR ( " failed to pin overlay register bo \n " ) ;
goto out_free_bo ;
}
2010-11-08 22:18:58 +03:00
overlay - > flip_addr = reg_bo - > gtt_offset ;
2010-08-12 12:35:00 +04:00
ret = i915_gem_object_set_to_gtt_domain ( reg_bo , true ) ;
if ( ret ) {
2011-08-16 23:34:10 +04:00
DRM_ERROR ( " failed to move overlay register bo into the GTT \n " ) ;
goto out_unpin_bo ;
}
2009-09-16 00:57:34 +04:00
}
/* init all values */
overlay - > color_key = 0x0101fe ;
overlay - > brightness = - 19 ;
overlay - > contrast = 75 ;
overlay - > saturation = 146 ;
2010-08-12 13:35:26 +04:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-16 00:57:34 +04:00
if ( ! regs )
2011-06-28 14:27:47 +04:00
goto out_unpin_bo ;
2009-09-16 00:57:34 +04:00
2012-04-17 01:07:43 +04:00
memset_io ( regs , 0 , sizeof ( struct overlay_registers ) ) ;
2009-09-16 00:57:34 +04:00
update_polyphase_filter ( regs ) ;
update_reg_attrs ( overlay , regs ) ;
2010-08-12 15:02:11 +04:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-16 00:57:34 +04:00
dev_priv - > overlay = overlay ;
2011-06-28 14:27:47 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2009-09-16 00:57:34 +04:00
DRM_INFO ( " initialized overlay support \n " ) ;
return ;
2010-08-12 12:35:00 +04:00
out_unpin_bo :
2011-06-28 14:27:47 +04:00
if ( ! OVERLAY_NEEDS_PHYSICAL ( dev ) )
i915_gem_object_unpin ( reg_bo ) ;
2009-09-16 00:57:34 +04:00
out_free_bo :
2010-11-08 22:18:58 +03:00
drm_gem_object_unreference ( & reg_bo - > base ) ;
2009-09-16 00:57:34 +04:00
out_free :
2011-06-28 14:27:47 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2009-09-16 00:57:34 +04:00
kfree ( overlay ) ;
return ;
}
void intel_cleanup_overlay ( struct drm_device * dev )
{
2010-08-12 12:28:50 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2009-09-16 00:57:34 +04:00
2010-08-12 13:50:36 +04:00
if ( ! dev_priv - > overlay )
return ;
2009-09-16 00:57:34 +04:00
2010-08-12 13:50:36 +04:00
/* The bo's should be free'd by the generic code already.
* Furthermore modesetting teardown happens beforehand so the
* hardware should be off already */
BUG_ON ( dev_priv - > overlay - > active ) ;
drm_gem_object_unreference_unlocked ( & dev_priv - > overlay - > reg_bo - > base ) ;
kfree ( dev_priv - > overlay ) ;
2009-09-16 00:57:34 +04:00
}
2010-08-04 23:26:07 +04:00
2010-08-19 11:19:30 +04:00
# ifdef CONFIG_DEBUG_FS
# include <linux/seq_file.h>
2010-08-04 23:26:07 +04:00
struct intel_overlay_error_state {
struct overlay_registers regs ;
unsigned long base ;
u32 dovsta ;
u32 isr ;
} ;
2012-04-17 01:07:43 +04:00
static struct overlay_registers __iomem *
2010-10-27 05:57:59 +04:00
intel_overlay_map_regs_atomic ( struct intel_overlay * overlay )
2010-08-19 11:19:30 +04:00
{
2010-10-27 05:57:59 +04:00
drm_i915_private_t * dev_priv = overlay - > dev - > dev_private ;
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs ;
2010-08-19 11:19:30 +04:00
if ( OVERLAY_NEEDS_PHYSICAL ( overlay - > dev ) )
2012-04-17 01:07:43 +04:00
/* Cast to make sparse happy, but it's wc memory anyway, so
* equivalent to the wc io mapping on X86 . */
regs = ( struct overlay_registers __iomem * )
overlay - > reg_bo - > phys_obj - > handle - > vaddr ;
2010-08-19 11:19:30 +04:00
else
regs = io_mapping_map_atomic_wc ( dev_priv - > mm . gtt_mapping ,
2010-10-27 05:57:59 +04:00
overlay - > reg_bo - > gtt_offset ) ;
2010-08-19 11:19:30 +04:00
return regs ;
}
static void intel_overlay_unmap_regs_atomic ( struct intel_overlay * overlay ,
2012-04-17 01:07:43 +04:00
struct overlay_registers __iomem * regs )
2010-08-19 11:19:30 +04:00
{
if ( ! OVERLAY_NEEDS_PHYSICAL ( overlay - > dev ) )
2010-10-27 05:57:59 +04:00
io_mapping_unmap_atomic ( regs ) ;
2010-08-19 11:19:30 +04:00
}
2010-08-04 23:26:07 +04:00
struct intel_overlay_error_state *
intel_overlay_capture_error_state ( struct drm_device * dev )
{
2011-08-16 23:34:10 +04:00
drm_i915_private_t * dev_priv = dev - > dev_private ;
2010-08-04 23:26:07 +04:00
struct intel_overlay * overlay = dev_priv - > overlay ;
struct intel_overlay_error_state * error ;
struct overlay_registers __iomem * regs ;
if ( ! overlay | | ! overlay - > active )
return NULL ;
error = kmalloc ( sizeof ( * error ) , GFP_ATOMIC ) ;
if ( error = = NULL )
return NULL ;
error - > dovsta = I915_READ ( DOVSTA ) ;
error - > isr = I915_READ ( ISR ) ;
2010-08-12 12:42:51 +04:00
if ( OVERLAY_NEEDS_PHYSICAL ( overlay - > dev ) )
2012-04-17 01:07:43 +04:00
error - > base = ( __force long ) overlay - > reg_bo - > phys_obj - > handle - > vaddr ;
2010-08-12 12:42:51 +04:00
else
2012-04-17 01:07:43 +04:00
error - > base = overlay - > reg_bo - > gtt_offset ;
2010-08-04 23:26:07 +04:00
regs = intel_overlay_map_regs_atomic ( overlay ) ;
if ( ! regs )
goto err ;
memcpy_fromio ( & error - > regs , regs , sizeof ( struct overlay_registers ) ) ;
2010-10-27 05:57:59 +04:00
intel_overlay_unmap_regs_atomic ( overlay , regs ) ;
2010-08-04 23:26:07 +04:00
return error ;
err :
kfree ( error ) ;
return NULL ;
}
void
intel_overlay_print_error_state ( struct seq_file * m , struct intel_overlay_error_state * error )
{
seq_printf ( m , " Overlay, status: 0x%08x, interrupt: 0x%08x \n " ,
error - > dovsta , error - > isr ) ;
seq_printf ( m , " Register file at 0x%08lx: \n " ,
error - > base ) ;
# define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
P ( OBUF_0Y ) ;
P ( OBUF_1Y ) ;
P ( OBUF_0U ) ;
P ( OBUF_0V ) ;
P ( OBUF_1U ) ;
P ( OBUF_1V ) ;
P ( OSTRIDE ) ;
P ( YRGB_VPH ) ;
P ( UV_VPH ) ;
P ( HORZ_PH ) ;
P ( INIT_PHS ) ;
P ( DWINPOS ) ;
P ( DWINSZ ) ;
P ( SWIDTH ) ;
P ( SWIDTHSW ) ;
P ( SHEIGHT ) ;
P ( YRGBSCALE ) ;
P ( UVSCALE ) ;
P ( OCLRC0 ) ;
P ( OCLRC1 ) ;
P ( DCLRKV ) ;
P ( DCLRKM ) ;
P ( SCLRKVH ) ;
P ( SCLRKVL ) ;
P ( SCLRKEN ) ;
P ( OCONFIG ) ;
P ( OCMD ) ;
P ( OSTART_0Y ) ;
P ( OSTART_1Y ) ;
P ( OSTART_0U ) ;
P ( OSTART_0V ) ;
P ( OSTART_1U ) ;
P ( OSTART_1V ) ;
P ( OTILEOFF_0Y ) ;
P ( OTILEOFF_1Y ) ;
P ( OTILEOFF_0U ) ;
P ( OTILEOFF_0V ) ;
P ( OTILEOFF_1U ) ;
P ( OTILEOFF_1V ) ;
P ( FASTHSCALE ) ;
P ( UVSCALEV ) ;
# undef P
}
2010-08-19 11:19:30 +04:00
# endif