2011-12-13 13:19:38 -08:00
/*
* Copyright © 2011 Intel Corporation
*
* 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 :
* Jesse Barnes < jbarnes @ virtuousgeek . org >
*
* New plane / sprite handling .
*
* The older chips had a separate interface for programming plane related
* registers ; newer ones are much simpler and we can use the new DRM plane
* support .
*/
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/drm_crtc.h>
# include <drm/drm_fourcc.h>
2013-04-24 18:52:38 +03:00
# include <drm/drm_rect.h>
2011-12-13 13:19:38 -08:00
# include "intel_drv.h"
2012-10-02 18:01:07 +01:00
# include <drm/i915_drm.h>
2011-12-13 13:19:38 -08:00
# include "i915_drv.h"
2014-04-29 13:35:46 +03:00
static int usecs_to_scanlines ( const struct drm_display_mode * mode , int usecs )
{
/* paranoia */
if ( ! mode - > crtc_htotal )
return 1 ;
return DIV_ROUND_UP ( usecs * mode - > crtc_clock , 1000 * mode - > crtc_htotal ) ;
}
static bool intel_pipe_update_start ( struct intel_crtc * crtc , uint32_t * start_vbl_count )
{
struct drm_device * dev = crtc - > base . dev ;
const struct drm_display_mode * mode = & crtc - > config . adjusted_mode ;
enum pipe pipe = crtc - > pipe ;
long timeout = msecs_to_jiffies_timeout ( 1 ) ;
int scanline , min , max , vblank_start ;
DEFINE_WAIT ( wait ) ;
WARN_ON ( ! mutex_is_locked ( & crtc - > base . mutex ) ) ;
vblank_start = mode - > crtc_vblank_start ;
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
vblank_start = DIV_ROUND_UP ( vblank_start , 2 ) ;
/* FIXME needs to be calibrated sensibly */
min = vblank_start - usecs_to_scanlines ( mode , 100 ) ;
max = vblank_start - 1 ;
if ( min < = 0 | | max < = 0 )
return false ;
if ( WARN_ON ( drm_vblank_get ( dev , pipe ) ) )
return false ;
local_irq_disable ( ) ;
2014-04-29 13:35:48 +03:00
trace_i915_pipe_update_start ( crtc , min , max ) ;
2014-04-29 13:35:46 +03:00
for ( ; ; ) {
/*
* prepare_to_wait ( ) has a memory barrier , which guarantees
* other CPUs can see the task state update by the time we
* read the scanline .
*/
prepare_to_wait ( & crtc - > vbl_wait , & wait , TASK_UNINTERRUPTIBLE ) ;
scanline = intel_get_crtc_scanline ( crtc ) ;
if ( scanline < min | | scanline > max )
break ;
if ( timeout < = 0 ) {
DRM_ERROR ( " Potential atomic update failure on pipe %c \n " ,
pipe_name ( crtc - > pipe ) ) ;
break ;
}
local_irq_enable ( ) ;
timeout = schedule_timeout ( timeout ) ;
local_irq_disable ( ) ;
}
finish_wait ( & crtc - > vbl_wait , & wait ) ;
drm_vblank_put ( dev , pipe ) ;
* start_vbl_count = dev - > driver - > get_vblank_counter ( dev , pipe ) ;
2014-04-29 13:35:48 +03:00
trace_i915_pipe_update_vblank_evaded ( crtc , min , max , * start_vbl_count ) ;
2014-04-29 13:35:46 +03:00
return true ;
}
static void intel_pipe_update_end ( struct intel_crtc * crtc , u32 start_vbl_count )
{
struct drm_device * dev = crtc - > base . dev ;
enum pipe pipe = crtc - > pipe ;
u32 end_vbl_count = dev - > driver - > get_vblank_counter ( dev , pipe ) ;
2014-04-29 13:35:48 +03:00
trace_i915_pipe_update_end ( crtc , end_vbl_count ) ;
2014-04-29 13:35:46 +03:00
local_irq_enable ( ) ;
if ( start_vbl_count ! = end_vbl_count )
DRM_ERROR ( " Atomic update failure on pipe %c (start=%u end=%u) \n " ,
pipe_name ( pipe ) , start_vbl_count , end_vbl_count ) ;
}
2014-04-29 13:35:47 +03:00
static void intel_update_primary_plane ( struct intel_crtc * crtc )
{
struct drm_i915_private * dev_priv = crtc - > base . dev - > dev_private ;
int reg = DSPCNTR ( crtc - > plane ) ;
if ( crtc - > primary_enabled )
I915_WRITE ( reg , I915_READ ( reg ) | DISPLAY_PLANE_ENABLE ) ;
else
I915_WRITE ( reg , I915_READ ( reg ) & ~ DISPLAY_PLANE_ENABLE ) ;
}
2013-04-02 11:22:20 -07:00
static void
2013-08-06 22:24:09 +03:00
vlv_update_plane ( struct drm_plane * dplane , struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
2013-04-02 11:22:20 -07:00
struct drm_i915_gem_object * obj , int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
uint32_t x , uint32_t y ,
uint32_t src_w , uint32_t src_h )
{
struct drm_device * dev = dplane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( dplane ) ;
2014-04-29 13:35:46 +03:00
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2013-04-02 11:22:20 -07:00
int pipe = intel_plane - > pipe ;
int plane = intel_plane - > plane ;
u32 sprctl ;
unsigned long sprsurf_offset , linear_offset ;
int pixel_size = drm_format_plane_cpp ( fb - > pixel_format , 0 ) ;
2014-04-29 13:35:46 +03:00
u32 start_vbl_count ;
bool atomic_update ;
2013-04-02 11:22:20 -07:00
sprctl = I915_READ ( SPCNTR ( pipe , plane ) ) ;
/* Mask out pixel format bits in case we change it */
sprctl & = ~ SP_PIXFORMAT_MASK ;
sprctl & = ~ SP_YUV_BYTE_ORDER_MASK ;
sprctl & = ~ SP_TILED ;
switch ( fb - > pixel_format ) {
case DRM_FORMAT_YUYV :
sprctl | = SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV ;
break ;
case DRM_FORMAT_YVYU :
sprctl | = SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU ;
break ;
case DRM_FORMAT_UYVY :
sprctl | = SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY ;
break ;
case DRM_FORMAT_VYUY :
sprctl | = SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY ;
break ;
case DRM_FORMAT_RGB565 :
sprctl | = SP_FORMAT_BGR565 ;
break ;
case DRM_FORMAT_XRGB8888 :
sprctl | = SP_FORMAT_BGRX8888 ;
break ;
case DRM_FORMAT_ARGB8888 :
sprctl | = SP_FORMAT_BGRA8888 ;
break ;
case DRM_FORMAT_XBGR2101010 :
sprctl | = SP_FORMAT_RGBX1010102 ;
break ;
case DRM_FORMAT_ABGR2101010 :
sprctl | = SP_FORMAT_RGBA1010102 ;
break ;
case DRM_FORMAT_XBGR8888 :
sprctl | = SP_FORMAT_RGBX8888 ;
break ;
case DRM_FORMAT_ABGR8888 :
sprctl | = SP_FORMAT_RGBA8888 ;
break ;
default :
/*
* If we get here one of the upper layers failed to filter
* out the unsupported plane formats
*/
BUG ( ) ;
break ;
}
2013-11-18 18:32:38 -08:00
/*
* Enable gamma to match primary / cursor plane behaviour .
* FIXME should be user controllable via propertiesa .
*/
sprctl | = SP_GAMMA_ENABLE ;
2013-04-02 11:22:20 -07:00
if ( obj - > tiling_mode ! = I915_TILING_NONE )
sprctl | = SP_TILED ;
sprctl | = SP_ENABLE ;
2013-08-06 22:24:11 +03:00
intel_update_sprite_watermarks ( dplane , crtc , src_w , pixel_size , true ,
2013-07-05 11:57:14 +03:00
src_w ! = crtc_w | | src_h ! = crtc_h ) ;
2013-04-02 11:22:20 -07:00
/* Sizes are 0 based */
src_w - - ;
src_h - - ;
crtc_w - - ;
crtc_h - - ;
linear_offset = y * fb - > pitches [ 0 ] + x * pixel_size ;
sprsurf_offset = intel_gen4_compute_page_offset ( & x , & y ,
obj - > tiling_mode ,
pixel_size ,
fb - > pitches [ 0 ] ) ;
linear_offset - = sprsurf_offset ;
2014-04-29 13:35:46 +03:00
atomic_update = intel_pipe_update_start ( intel_crtc , & start_vbl_count ) ;
2014-04-29 13:35:47 +03:00
intel_update_primary_plane ( intel_crtc ) ;
2014-01-17 20:09:03 +02:00
I915_WRITE ( SPSTRIDE ( pipe , plane ) , fb - > pitches [ 0 ] ) ;
I915_WRITE ( SPPOS ( pipe , plane ) , ( crtc_y < < 16 ) | crtc_x ) ;
2013-04-02 11:22:20 -07:00
if ( obj - > tiling_mode ! = I915_TILING_NONE )
I915_WRITE ( SPTILEOFF ( pipe , plane ) , ( y < < 16 ) | x ) ;
else
I915_WRITE ( SPLINOFF ( pipe , plane ) , linear_offset ) ;
I915_WRITE ( SPSIZE ( pipe , plane ) , ( crtc_h < < 16 ) | crtc_w ) ;
I915_WRITE ( SPCNTR ( pipe , plane ) , sprctl ) ;
2014-01-24 10:31:44 +01:00
I915_WRITE ( SPSURF ( pipe , plane ) , i915_gem_obj_ggtt_offset ( obj ) +
sprsurf_offset ) ;
2014-04-29 13:35:47 +03:00
intel_flush_primary_plane ( dev_priv , intel_crtc - > plane ) ;
2014-04-29 13:35:46 +03:00
if ( atomic_update )
intel_pipe_update_end ( intel_crtc , start_vbl_count ) ;
2013-04-02 11:22:20 -07:00
}
static void
2013-08-06 22:24:09 +03:00
vlv_disable_plane ( struct drm_plane * dplane , struct drm_crtc * crtc )
2013-04-02 11:22:20 -07:00
{
struct drm_device * dev = dplane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( dplane ) ;
2014-04-29 13:35:46 +03:00
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2013-04-02 11:22:20 -07:00
int pipe = intel_plane - > pipe ;
int plane = intel_plane - > plane ;
2014-04-29 13:35:46 +03:00
u32 start_vbl_count ;
bool atomic_update ;
atomic_update = intel_pipe_update_start ( intel_crtc , & start_vbl_count ) ;
2013-04-02 11:22:20 -07:00
2014-04-29 13:35:47 +03:00
intel_update_primary_plane ( intel_crtc ) ;
2013-04-02 11:22:20 -07:00
I915_WRITE ( SPCNTR ( pipe , plane ) , I915_READ ( SPCNTR ( pipe , plane ) ) &
~ SP_ENABLE ) ;
/* Activate double buffered register update */
2014-01-24 10:31:44 +01:00
I915_WRITE ( SPSURF ( pipe , plane ) , 0 ) ;
2014-04-29 13:35:47 +03:00
intel_flush_primary_plane ( dev_priv , intel_crtc - > plane ) ;
2013-08-06 22:24:12 +03:00
2014-04-29 13:35:46 +03:00
if ( atomic_update )
intel_pipe_update_end ( intel_crtc , start_vbl_count ) ;
2013-08-06 22:24:12 +03:00
intel_update_sprite_watermarks ( dplane , crtc , 0 , 0 , false , false ) ;
2013-04-02 11:22:20 -07:00
}
static int
vlv_update_colorkey ( struct drm_plane * dplane ,
struct drm_intel_sprite_colorkey * key )
{
struct drm_device * dev = dplane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( dplane ) ;
int pipe = intel_plane - > pipe ;
int plane = intel_plane - > plane ;
u32 sprctl ;
if ( key - > flags & I915_SET_COLORKEY_DESTINATION )
return - EINVAL ;
I915_WRITE ( SPKEYMINVAL ( pipe , plane ) , key - > min_value ) ;
I915_WRITE ( SPKEYMAXVAL ( pipe , plane ) , key - > max_value ) ;
I915_WRITE ( SPKEYMSK ( pipe , plane ) , key - > channel_mask ) ;
sprctl = I915_READ ( SPCNTR ( pipe , plane ) ) ;
sprctl & = ~ SP_SOURCE_KEY ;
if ( key - > flags & I915_SET_COLORKEY_SOURCE )
sprctl | = SP_SOURCE_KEY ;
I915_WRITE ( SPCNTR ( pipe , plane ) , sprctl ) ;
POSTING_READ ( SPKEYMSK ( pipe , plane ) ) ;
return 0 ;
}
static void
vlv_get_colorkey ( struct drm_plane * dplane ,
struct drm_intel_sprite_colorkey * key )
{
struct drm_device * dev = dplane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( dplane ) ;
int pipe = intel_plane - > pipe ;
int plane = intel_plane - > plane ;
u32 sprctl ;
key - > min_value = I915_READ ( SPKEYMINVAL ( pipe , plane ) ) ;
key - > max_value = I915_READ ( SPKEYMAXVAL ( pipe , plane ) ) ;
key - > channel_mask = I915_READ ( SPKEYMSK ( pipe , plane ) ) ;
sprctl = I915_READ ( SPCNTR ( pipe , plane ) ) ;
if ( sprctl & SP_SOURCE_KEY )
key - > flags = I915_SET_COLORKEY_SOURCE ;
else
key - > flags = I915_SET_COLORKEY_NONE ;
}
2011-12-13 13:19:38 -08:00
static void
2013-08-06 22:24:09 +03:00
ivb_update_plane ( struct drm_plane * plane , struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
2011-12-13 13:19:38 -08:00
struct drm_i915_gem_object * obj , int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
uint32_t x , uint32_t y ,
uint32_t src_w , uint32_t src_h )
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2014-04-29 13:35:46 +03:00
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2011-12-13 13:19:38 -08:00
int pipe = intel_plane - > pipe ;
u32 sprctl , sprscale = 0 ;
2012-10-26 18:20:12 +01:00
unsigned long sprsurf_offset , linear_offset ;
2012-10-31 17:50:20 +02:00
int pixel_size = drm_format_plane_cpp ( fb - > pixel_format , 0 ) ;
2014-04-29 13:35:46 +03:00
u32 start_vbl_count ;
bool atomic_update ;
2011-12-13 13:19:38 -08:00
sprctl = I915_READ ( SPRCTL ( pipe ) ) ;
/* Mask out pixel format bits in case we change it */
sprctl & = ~ SPRITE_PIXFORMAT_MASK ;
sprctl & = ~ SPRITE_RGB_ORDER_RGBX ;
sprctl & = ~ SPRITE_YUV_BYTE_ORDER_MASK ;
2012-06-26 13:10:11 -07:00
sprctl & = ~ SPRITE_TILED ;
2011-12-13 13:19:38 -08:00
switch ( fb - > pixel_format ) {
case DRM_FORMAT_XBGR8888 :
2012-08-23 12:08:57 +05:30
sprctl | = SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX ;
2011-12-13 13:19:38 -08:00
break ;
case DRM_FORMAT_XRGB8888 :
2012-08-23 12:08:57 +05:30
sprctl | = SPRITE_FORMAT_RGBX888 ;
2011-12-13 13:19:38 -08:00
break ;
case DRM_FORMAT_YUYV :
sprctl | = SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV ;
break ;
case DRM_FORMAT_YVYU :
sprctl | = SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU ;
break ;
case DRM_FORMAT_UYVY :
sprctl | = SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY ;
break ;
case DRM_FORMAT_VYUY :
sprctl | = SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY ;
break ;
default :
2012-10-31 17:50:21 +02:00
BUG ( ) ;
2011-12-13 13:19:38 -08:00
}
2013-11-18 18:32:38 -08:00
/*
* Enable gamma to match primary / cursor plane behaviour .
* FIXME should be user controllable via propertiesa .
*/
sprctl | = SPRITE_GAMMA_ENABLE ;
2011-12-13 13:19:38 -08:00
if ( obj - > tiling_mode ! = I915_TILING_NONE )
sprctl | = SPRITE_TILED ;
2013-11-03 13:47:27 +02:00
if ( IS_HASWELL ( dev ) | | IS_BROADWELL ( dev ) )
2013-08-23 19:51:28 -03:00
sprctl & = ~ SPRITE_TRICKLE_FEED_DISABLE ;
else
sprctl | = SPRITE_TRICKLE_FEED_DISABLE ;
2011-12-13 13:19:38 -08:00
sprctl | = SPRITE_ENABLE ;
2013-11-02 21:07:39 -07:00
if ( IS_HASWELL ( dev ) | | IS_BROADWELL ( dev ) )
2013-01-18 19:11:38 +02:00
sprctl | = SPRITE_PIPE_CSC_ENABLE ;
2013-08-06 22:24:11 +03:00
intel_update_sprite_watermarks ( plane , crtc , src_w , pixel_size , true ,
2013-07-05 11:57:14 +03:00
src_w ! = crtc_w | | src_h ! = crtc_h ) ;
2011-12-13 13:19:38 -08:00
/* Sizes are 0 based */
src_w - - ;
src_h - - ;
crtc_w - - ;
crtc_h - - ;
2013-12-05 15:51:39 +02:00
if ( crtc_w ! = src_w | | crtc_h ! = src_h )
2011-12-13 13:19:38 -08:00
sprscale = SPRITE_SCALE_ENABLE | ( src_w < < 16 ) | src_h ;
2012-12-19 12:14:22 +00:00
linear_offset = y * fb - > pitches [ 0 ] + x * pixel_size ;
2012-10-26 18:20:12 +01:00
sprsurf_offset =
2013-02-21 20:04:31 +00:00
intel_gen4_compute_page_offset ( & x , & y , obj - > tiling_mode ,
pixel_size , fb - > pitches [ 0 ] ) ;
2012-10-26 18:20:12 +01:00
linear_offset - = sprsurf_offset ;
2014-04-29 13:35:46 +03:00
atomic_update = intel_pipe_update_start ( intel_crtc , & start_vbl_count ) ;
2014-04-29 13:35:47 +03:00
intel_update_primary_plane ( intel_crtc ) ;
2014-01-17 20:09:03 +02:00
I915_WRITE ( SPRSTRIDE ( pipe ) , fb - > pitches [ 0 ] ) ;
I915_WRITE ( SPRPOS ( pipe ) , ( crtc_y < < 16 ) | crtc_x ) ;
2012-10-26 18:20:12 +01:00
/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
* register */
2013-11-02 21:07:33 -07:00
if ( IS_HASWELL ( dev ) | | IS_BROADWELL ( dev ) )
2012-10-26 18:20:11 +01:00
I915_WRITE ( SPROFFSET ( pipe ) , ( y < < 16 ) | x ) ;
2012-10-26 18:20:12 +01:00
else if ( obj - > tiling_mode ! = I915_TILING_NONE )
2011-12-13 13:19:38 -08:00
I915_WRITE ( SPRTILEOFF ( pipe ) , ( y < < 16 ) | x ) ;
2012-10-26 18:20:12 +01:00
else
I915_WRITE ( SPRLINOFF ( pipe ) , linear_offset ) ;
2012-10-26 18:20:11 +01:00
2011-12-13 13:19:38 -08:00
I915_WRITE ( SPRSIZE ( pipe ) , ( crtc_h < < 16 ) | crtc_w ) ;
2012-10-22 18:19:27 +01:00
if ( intel_plane - > can_scale )
I915_WRITE ( SPRSCALE ( pipe ) , sprscale ) ;
2011-12-13 13:19:38 -08:00
I915_WRITE ( SPRCTL ( pipe ) , sprctl ) ;
2014-01-24 10:31:44 +01:00
I915_WRITE ( SPRSURF ( pipe ) ,
i915_gem_obj_ggtt_offset ( obj ) + sprsurf_offset ) ;
2014-04-29 13:35:47 +03:00
intel_flush_primary_plane ( dev_priv , intel_crtc - > plane ) ;
2014-04-29 13:35:46 +03:00
if ( atomic_update )
intel_pipe_update_end ( intel_crtc , start_vbl_count ) ;
2011-12-13 13:19:38 -08:00
}
static void
2013-08-06 22:24:09 +03:00
ivb_disable_plane ( struct drm_plane * plane , struct drm_crtc * crtc )
2011-12-13 13:19:38 -08:00
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2014-04-29 13:35:46 +03:00
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2011-12-13 13:19:38 -08:00
int pipe = intel_plane - > pipe ;
2014-04-29 13:35:46 +03:00
u32 start_vbl_count ;
bool atomic_update ;
atomic_update = intel_pipe_update_start ( intel_crtc , & start_vbl_count ) ;
2011-12-13 13:19:38 -08:00
2014-04-29 13:35:47 +03:00
intel_update_primary_plane ( intel_crtc ) ;
2011-12-13 13:19:38 -08:00
I915_WRITE ( SPRCTL ( pipe ) , I915_READ ( SPRCTL ( pipe ) ) & ~ SPRITE_ENABLE ) ;
/* Can't leave the scaler enabled... */
2012-10-22 18:19:27 +01:00
if ( intel_plane - > can_scale )
I915_WRITE ( SPRSCALE ( pipe ) , 0 ) ;
2011-12-13 13:19:38 -08:00
/* Activate double buffered register update */
2014-01-24 10:31:44 +01:00
I915_WRITE ( SPRSURF ( pipe ) , 0 ) ;
2014-04-29 13:35:47 +03:00
intel_flush_primary_plane ( dev_priv , intel_crtc - > plane ) ;
2012-04-18 17:12:26 +01:00
2014-04-29 13:35:46 +03:00
if ( atomic_update )
intel_pipe_update_end ( intel_crtc , start_vbl_count ) ;
2013-12-05 15:51:41 +02:00
/*
* Avoid underruns when disabling the sprite .
* FIXME remove once watermark updates are done properly .
*/
intel_wait_for_vblank ( dev , pipe ) ;
2013-08-06 22:24:11 +03:00
intel_update_sprite_watermarks ( plane , crtc , 0 , 0 , false , false ) ;
2011-12-13 13:19:38 -08:00
}
2012-01-03 08:05:39 -08:00
static int
ivb_update_colorkey ( struct drm_plane * plane ,
struct drm_intel_sprite_colorkey * key )
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane ;
u32 sprctl ;
int ret = 0 ;
intel_plane = to_intel_plane ( plane ) ;
I915_WRITE ( SPRKEYVAL ( intel_plane - > pipe ) , key - > min_value ) ;
I915_WRITE ( SPRKEYMAX ( intel_plane - > pipe ) , key - > max_value ) ;
I915_WRITE ( SPRKEYMSK ( intel_plane - > pipe ) , key - > channel_mask ) ;
sprctl = I915_READ ( SPRCTL ( intel_plane - > pipe ) ) ;
sprctl & = ~ ( SPRITE_SOURCE_KEY | SPRITE_DEST_KEY ) ;
if ( key - > flags & I915_SET_COLORKEY_DESTINATION )
sprctl | = SPRITE_DEST_KEY ;
else if ( key - > flags & I915_SET_COLORKEY_SOURCE )
sprctl | = SPRITE_SOURCE_KEY ;
I915_WRITE ( SPRCTL ( intel_plane - > pipe ) , sprctl ) ;
POSTING_READ ( SPRKEYMSK ( intel_plane - > pipe ) ) ;
return ret ;
}
static void
ivb_get_colorkey ( struct drm_plane * plane , struct drm_intel_sprite_colorkey * key )
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane ;
u32 sprctl ;
intel_plane = to_intel_plane ( plane ) ;
key - > min_value = I915_READ ( SPRKEYVAL ( intel_plane - > pipe ) ) ;
key - > max_value = I915_READ ( SPRKEYMAX ( intel_plane - > pipe ) ) ;
key - > channel_mask = I915_READ ( SPRKEYMSK ( intel_plane - > pipe ) ) ;
key - > flags = 0 ;
sprctl = I915_READ ( SPRCTL ( intel_plane - > pipe ) ) ;
if ( sprctl & SPRITE_DEST_KEY )
key - > flags = I915_SET_COLORKEY_DESTINATION ;
else if ( sprctl & SPRITE_SOURCE_KEY )
key - > flags = I915_SET_COLORKEY_SOURCE ;
else
key - > flags = I915_SET_COLORKEY_NONE ;
}
2011-12-13 13:19:38 -08:00
static void
2013-08-06 22:24:09 +03:00
ilk_update_plane ( struct drm_plane * plane , struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
2011-12-13 13:19:38 -08:00
struct drm_i915_gem_object * obj , int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
uint32_t x , uint32_t y ,
uint32_t src_w , uint32_t src_h )
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2014-04-29 13:35:46 +03:00
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2012-10-31 17:50:20 +02:00
int pipe = intel_plane - > pipe ;
2012-10-26 18:20:12 +01:00
unsigned long dvssurf_offset , linear_offset ;
2012-04-14 22:14:26 +01:00
u32 dvscntr , dvsscale ;
2012-10-31 17:50:20 +02:00
int pixel_size = drm_format_plane_cpp ( fb - > pixel_format , 0 ) ;
2014-04-29 13:35:46 +03:00
u32 start_vbl_count ;
bool atomic_update ;
2011-12-13 13:19:38 -08:00
dvscntr = I915_READ ( DVSCNTR ( pipe ) ) ;
/* Mask out pixel format bits in case we change it */
dvscntr & = ~ DVS_PIXFORMAT_MASK ;
2012-02-27 12:40:10 -08:00
dvscntr & = ~ DVS_RGB_ORDER_XBGR ;
2011-12-13 13:19:38 -08:00
dvscntr & = ~ DVS_YUV_BYTE_ORDER_MASK ;
2012-07-13 15:50:33 +03:00
dvscntr & = ~ DVS_TILED ;
2011-12-13 13:19:38 -08:00
switch ( fb - > pixel_format ) {
case DRM_FORMAT_XBGR8888 :
2012-02-27 12:40:10 -08:00
dvscntr | = DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR ;
2011-12-13 13:19:38 -08:00
break ;
case DRM_FORMAT_XRGB8888 :
2012-02-27 12:40:10 -08:00
dvscntr | = DVS_FORMAT_RGBX888 ;
2011-12-13 13:19:38 -08:00
break ;
case DRM_FORMAT_YUYV :
dvscntr | = DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV ;
break ;
case DRM_FORMAT_YVYU :
dvscntr | = DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU ;
break ;
case DRM_FORMAT_UYVY :
dvscntr | = DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY ;
break ;
case DRM_FORMAT_VYUY :
dvscntr | = DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY ;
break ;
default :
2012-10-31 17:50:21 +02:00
BUG ( ) ;
2011-12-13 13:19:38 -08:00
}
2013-11-18 18:32:38 -08:00
/*
* Enable gamma to match primary / cursor plane behaviour .
* FIXME should be user controllable via propertiesa .
*/
dvscntr | = DVS_GAMMA_ENABLE ;
2011-12-13 13:19:38 -08:00
if ( obj - > tiling_mode ! = I915_TILING_NONE )
dvscntr | = DVS_TILED ;
2012-04-10 11:41:49 +01:00
if ( IS_GEN6 ( dev ) )
dvscntr | = DVS_TRICKLE_FEED_DISABLE ; /* must disable */
2011-12-13 13:19:38 -08:00
dvscntr | = DVS_ENABLE ;
2013-08-06 22:24:11 +03:00
intel_update_sprite_watermarks ( plane , crtc , src_w , pixel_size , true ,
2013-07-05 11:57:14 +03:00
src_w ! = crtc_w | | src_h ! = crtc_h ) ;
2011-12-13 13:19:38 -08:00
/* Sizes are 0 based */
src_w - - ;
src_h - - ;
crtc_w - - ;
crtc_h - - ;
2012-04-14 22:14:26 +01:00
dvsscale = 0 ;
2013-12-05 15:51:31 +02:00
if ( crtc_w ! = src_w | | crtc_h ! = src_h )
2011-12-13 13:19:38 -08:00
dvsscale = DVS_SCALE_ENABLE | ( src_w < < 16 ) | src_h ;
2012-12-19 12:14:22 +00:00
linear_offset = y * fb - > pitches [ 0 ] + x * pixel_size ;
2012-10-26 18:20:12 +01:00
dvssurf_offset =
2013-02-21 20:04:31 +00:00
intel_gen4_compute_page_offset ( & x , & y , obj - > tiling_mode ,
pixel_size , fb - > pitches [ 0 ] ) ;
2012-10-26 18:20:12 +01:00
linear_offset - = dvssurf_offset ;
2014-04-29 13:35:46 +03:00
atomic_update = intel_pipe_update_start ( intel_crtc , & start_vbl_count ) ;
2014-04-29 13:35:47 +03:00
intel_update_primary_plane ( intel_crtc ) ;
2014-01-17 20:09:03 +02:00
I915_WRITE ( DVSSTRIDE ( pipe ) , fb - > pitches [ 0 ] ) ;
I915_WRITE ( DVSPOS ( pipe ) , ( crtc_y < < 16 ) | crtc_x ) ;
2012-10-26 18:20:12 +01:00
if ( obj - > tiling_mode ! = I915_TILING_NONE )
2011-12-13 13:19:38 -08:00
I915_WRITE ( DVSTILEOFF ( pipe ) , ( y < < 16 ) | x ) ;
2012-10-26 18:20:12 +01:00
else
I915_WRITE ( DVSLINOFF ( pipe ) , linear_offset ) ;
2011-12-13 13:19:38 -08:00
I915_WRITE ( DVSSIZE ( pipe ) , ( crtc_h < < 16 ) | crtc_w ) ;
I915_WRITE ( DVSSCALE ( pipe ) , dvsscale ) ;
I915_WRITE ( DVSCNTR ( pipe ) , dvscntr ) ;
2014-01-24 10:31:44 +01:00
I915_WRITE ( DVSSURF ( pipe ) ,
i915_gem_obj_ggtt_offset ( obj ) + dvssurf_offset ) ;
2014-04-29 13:35:47 +03:00
intel_flush_primary_plane ( dev_priv , intel_crtc - > plane ) ;
2014-04-29 13:35:46 +03:00
if ( atomic_update )
intel_pipe_update_end ( intel_crtc , start_vbl_count ) ;
2011-12-13 13:19:38 -08:00
}
static void
2013-08-06 22:24:09 +03:00
ilk_disable_plane ( struct drm_plane * plane , struct drm_crtc * crtc )
2011-12-13 13:19:38 -08:00
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2014-04-29 13:35:46 +03:00
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2011-12-13 13:19:38 -08:00
int pipe = intel_plane - > pipe ;
2014-04-29 13:35:46 +03:00
u32 start_vbl_count ;
bool atomic_update ;
atomic_update = intel_pipe_update_start ( intel_crtc , & start_vbl_count ) ;
2011-12-13 13:19:38 -08:00
2014-04-29 13:35:47 +03:00
intel_update_primary_plane ( intel_crtc ) ;
2011-12-13 13:19:38 -08:00
I915_WRITE ( DVSCNTR ( pipe ) , I915_READ ( DVSCNTR ( pipe ) ) & ~ DVS_ENABLE ) ;
/* Disable the scaler */
I915_WRITE ( DVSSCALE ( pipe ) , 0 ) ;
/* Flush double buffered register updates */
2014-01-24 10:31:44 +01:00
I915_WRITE ( DVSSURF ( pipe ) , 0 ) ;
2014-04-29 13:35:47 +03:00
intel_flush_primary_plane ( dev_priv , intel_crtc - > plane ) ;
2013-08-06 22:24:12 +03:00
2014-04-29 13:35:46 +03:00
if ( atomic_update )
intel_pipe_update_end ( intel_crtc , start_vbl_count ) ;
2013-12-05 15:51:41 +02:00
/*
* Avoid underruns when disabling the sprite .
* FIXME remove once watermark updates are done properly .
*/
intel_wait_for_vblank ( dev , pipe ) ;
2013-08-06 22:24:12 +03:00
intel_update_sprite_watermarks ( plane , crtc , 0 , 0 , false , false ) ;
2011-12-13 13:19:38 -08:00
}
2011-12-13 13:19:39 -08:00
static void
2014-04-29 13:35:47 +03:00
intel_post_enable_primary ( struct drm_crtc * crtc )
2011-12-13 13:19:39 -08:00
{
struct drm_device * dev = crtc - > dev ;
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2013-10-01 18:02:16 +03:00
2013-10-01 18:02:17 +03:00
/*
* FIXME IPS should be fine as long as one plane is
* enabled , but in practice it seems to have problems
* when going from primary only to sprite only and vice
* versa .
*/
if ( intel_crtc - > config . ips_enabled ) {
intel_wait_for_vblank ( dev , intel_crtc - > pipe ) ;
hsw_enable_ips ( intel_crtc ) ;
}
2013-10-01 18:02:12 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
2012-06-13 17:36:55 +01:00
intel_update_fbc ( dev ) ;
2013-10-01 18:02:12 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2011-12-13 13:19:39 -08:00
}
static void
2014-04-29 13:35:47 +03:00
intel_pre_disable_primary ( struct drm_crtc * crtc )
2011-12-13 13:19:39 -08:00
{
struct drm_device * dev = crtc - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2013-10-01 18:02:12 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
2013-10-01 18:02:16 +03:00
if ( dev_priv - > fbc . plane = = intel_crtc - > plane )
intel_disable_fbc ( dev ) ;
2013-10-01 18:02:12 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2013-10-01 18:02:16 +03:00
2013-10-01 18:02:17 +03:00
/*
* FIXME IPS should be fine as long as one plane is
* enabled , but in practice it seems to have problems
* when going from primary only to sprite only and vice
* versa .
*/
hsw_disable_ips ( intel_crtc ) ;
2011-12-13 13:19:39 -08:00
}
2012-01-03 08:05:39 -08:00
static int
2012-04-10 11:41:49 +01:00
ilk_update_colorkey ( struct drm_plane * plane ,
2012-01-03 08:05:39 -08:00
struct drm_intel_sprite_colorkey * key )
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane ;
u32 dvscntr ;
int ret = 0 ;
intel_plane = to_intel_plane ( plane ) ;
I915_WRITE ( DVSKEYVAL ( intel_plane - > pipe ) , key - > min_value ) ;
I915_WRITE ( DVSKEYMAX ( intel_plane - > pipe ) , key - > max_value ) ;
I915_WRITE ( DVSKEYMSK ( intel_plane - > pipe ) , key - > channel_mask ) ;
dvscntr = I915_READ ( DVSCNTR ( intel_plane - > pipe ) ) ;
dvscntr & = ~ ( DVS_SOURCE_KEY | DVS_DEST_KEY ) ;
if ( key - > flags & I915_SET_COLORKEY_DESTINATION )
dvscntr | = DVS_DEST_KEY ;
else if ( key - > flags & I915_SET_COLORKEY_SOURCE )
dvscntr | = DVS_SOURCE_KEY ;
I915_WRITE ( DVSCNTR ( intel_plane - > pipe ) , dvscntr ) ;
POSTING_READ ( DVSKEYMSK ( intel_plane - > pipe ) ) ;
return ret ;
}
static void
2012-04-10 11:41:49 +01:00
ilk_get_colorkey ( struct drm_plane * plane , struct drm_intel_sprite_colorkey * key )
2012-01-03 08:05:39 -08:00
{
struct drm_device * dev = plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane ;
u32 dvscntr ;
intel_plane = to_intel_plane ( plane ) ;
key - > min_value = I915_READ ( DVSKEYVAL ( intel_plane - > pipe ) ) ;
key - > max_value = I915_READ ( DVSKEYMAX ( intel_plane - > pipe ) ) ;
key - > channel_mask = I915_READ ( DVSKEYMSK ( intel_plane - > pipe ) ) ;
key - > flags = 0 ;
dvscntr = I915_READ ( DVSCNTR ( intel_plane - > pipe ) ) ;
if ( dvscntr & DVS_DEST_KEY )
key - > flags = I915_SET_COLORKEY_DESTINATION ;
else if ( dvscntr & DVS_SOURCE_KEY )
key - > flags = I915_SET_COLORKEY_SOURCE ;
else
key - > flags = I915_SET_COLORKEY_NONE ;
}
2013-04-24 18:52:38 +03:00
static bool
format_is_yuv ( uint32_t format )
{
switch ( format ) {
case DRM_FORMAT_YUYV :
case DRM_FORMAT_UYVY :
case DRM_FORMAT_VYUY :
case DRM_FORMAT_YVYU :
return true ;
default :
return false ;
}
}
2013-12-05 15:51:40 +02:00
static bool colorkey_enabled ( struct intel_plane * intel_plane )
{
struct drm_intel_sprite_colorkey key ;
intel_plane - > get_colorkey ( & intel_plane - > base , & key ) ;
return key . flags ! = I915_SET_COLORKEY_NONE ;
}
2011-12-13 13:19:38 -08:00
static int
intel_update_plane ( struct drm_plane * plane , struct drm_crtc * crtc ,
struct drm_framebuffer * fb , int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
uint32_t src_x , uint32_t src_y ,
uint32_t src_w , uint32_t src_h )
{
struct drm_device * dev = plane - > dev ;
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2013-10-01 18:02:14 +03:00
struct intel_framebuffer * intel_fb = to_intel_framebuffer ( fb ) ;
struct drm_i915_gem_object * obj = intel_fb - > obj ;
struct drm_i915_gem_object * old_obj = intel_plane - > obj ;
int ret ;
2014-04-29 13:35:47 +03:00
bool primary_enabled ;
2013-04-24 18:52:38 +03:00
bool visible ;
int hscale , vscale ;
int max_scale , min_scale ;
int pixel_size = drm_format_plane_cpp ( fb - > pixel_format , 0 ) ;
struct drm_rect src = {
/* sample coordinates in 16.16 fixed point */
. x1 = src_x ,
. x2 = src_x + src_w ,
. y1 = src_y ,
. y2 = src_y + src_h ,
} ;
struct drm_rect dst = {
/* integer pixels */
. x1 = crtc_x ,
. x2 = crtc_x + crtc_w ,
. y1 = crtc_y ,
. y2 = crtc_y + crtc_h ,
} ;
const struct drm_rect clip = {
2013-10-01 18:02:11 +03:00
. x2 = intel_crtc - > active ? intel_crtc - > config . pipe_src_w : 0 ,
. y2 = intel_crtc - > active ? intel_crtc - > config . pipe_src_h : 0 ,
2013-04-24 18:52:38 +03:00
} ;
2013-10-01 18:02:15 +03:00
const struct {
int crtc_x , crtc_y ;
unsigned int crtc_w , crtc_h ;
uint32_t src_x , src_y , src_w , src_h ;
} orig = {
. crtc_x = crtc_x ,
. crtc_y = crtc_y ,
. crtc_w = crtc_w ,
. crtc_h = crtc_h ,
. src_x = src_x ,
. src_y = src_y ,
. src_w = src_w ,
. src_h = src_h ,
} ;
2013-03-26 09:25:43 -07:00
2013-04-24 18:52:38 +03:00
/* Don't modify another pipe's plane */
if ( intel_plane - > pipe ! = intel_crtc - > pipe ) {
DRM_DEBUG_KMS ( " Wrong plane <-> crtc mapping \n " ) ;
2011-12-13 13:19:38 -08:00
return - EINVAL ;
2013-04-24 18:52:38 +03:00
}
2011-12-13 13:19:38 -08:00
2013-04-24 18:52:38 +03:00
/* FIXME check all gen limits */
if ( fb - > width < 3 | | fb - > height < 3 | | fb - > pitches [ 0 ] > 16384 ) {
DRM_DEBUG_KMS ( " Unsuitable framebuffer for plane \n " ) ;
2011-12-13 13:19:38 -08:00
return - EINVAL ;
2013-04-24 18:52:38 +03:00
}
2011-12-13 13:19:38 -08:00
2012-10-29 15:14:51 +00:00
/* Sprite planes can be linear or x-tiled surfaces */
switch ( obj - > tiling_mode ) {
case I915_TILING_NONE :
case I915_TILING_X :
break ;
default :
2013-04-24 18:52:38 +03:00
DRM_DEBUG_KMS ( " Unsupported tiling mode \n " ) ;
2012-10-29 15:14:51 +00:00
return - EINVAL ;
}
2013-04-24 18:52:39 +03:00
/*
* FIXME the following code does a bunch of fuzzy adjustments to the
* coordinates and sizes . We probably need some way to decide whether
* more strict checking should be done instead .
*/
2013-04-24 18:52:38 +03:00
max_scale = intel_plane - > max_downscale < < 16 ;
min_scale = intel_plane - > can_scale ? 1 : ( 1 < < 16 ) ;
2013-04-24 18:52:39 +03:00
hscale = drm_rect_calc_hscale_relaxed ( & src , & dst , min_scale , max_scale ) ;
BUG_ON ( hscale < 0 ) ;
2013-04-24 18:52:38 +03:00
2013-04-24 18:52:39 +03:00
vscale = drm_rect_calc_vscale_relaxed ( & src , & dst , min_scale , max_scale ) ;
BUG_ON ( vscale < 0 ) ;
2011-12-13 13:19:38 -08:00
2013-04-24 18:52:38 +03:00
visible = drm_rect_clip_scaled ( & src , & dst , & clip , hscale , vscale ) ;
2011-12-13 13:19:38 -08:00
2013-04-24 18:52:38 +03:00
crtc_x = dst . x1 ;
crtc_y = dst . y1 ;
crtc_w = drm_rect_width ( & dst ) ;
crtc_h = drm_rect_height ( & dst ) ;
2012-10-22 18:19:27 +01:00
2013-04-24 18:52:38 +03:00
if ( visible ) {
2013-04-24 18:52:39 +03:00
/* check again in case clipping clamped the results */
hscale = drm_rect_calc_hscale ( & src , & dst , min_scale , max_scale ) ;
if ( hscale < 0 ) {
DRM_DEBUG_KMS ( " Horizontal scaling factor out of limits \n " ) ;
drm_rect_debug_print ( & src , true ) ;
drm_rect_debug_print ( & dst , false ) ;
return hscale ;
}
vscale = drm_rect_calc_vscale ( & src , & dst , min_scale , max_scale ) ;
if ( vscale < 0 ) {
DRM_DEBUG_KMS ( " Vertical scaling factor out of limits \n " ) ;
drm_rect_debug_print ( & src , true ) ;
drm_rect_debug_print ( & dst , false ) ;
return vscale ;
}
2013-04-24 18:52:38 +03:00
/* Make the source viewport size an exact multiple of the scaling factors. */
drm_rect_adjust_size ( & src ,
drm_rect_width ( & dst ) * hscale - drm_rect_width ( & src ) ,
drm_rect_height ( & dst ) * vscale - drm_rect_height ( & src ) ) ;
/* sanity check to make sure the src viewport wasn't enlarged */
WARN_ON ( src . x1 < ( int ) src_x | |
src . y1 < ( int ) src_y | |
src . x2 > ( int ) ( src_x + src_w ) | |
src . y2 > ( int ) ( src_y + src_h ) ) ;
/*
* Hardware doesn ' t handle subpixel coordinates .
* Adjust to ( macro ) pixel boundary , but be careful not to
* increase the source viewport size , because that could
* push the downscaling factor out of bounds .
*/
src_x = src . x1 > > 16 ;
src_w = drm_rect_width ( & src ) > > 16 ;
src_y = src . y1 > > 16 ;
src_h = drm_rect_height ( & src ) > > 16 ;
if ( format_is_yuv ( fb - > pixel_format ) ) {
src_x & = ~ 1 ;
src_w & = ~ 1 ;
/*
* Must keep src and dst the
* same if we can ' t scale .
*/
if ( ! intel_plane - > can_scale )
crtc_w & = ~ 1 ;
if ( crtc_w = = 0 )
visible = false ;
}
}
/* Check size restrictions when scaling */
if ( visible & & ( src_w ! = crtc_w | | src_h ! = crtc_h ) ) {
unsigned int width_bytes ;
WARN_ON ( ! intel_plane - > can_scale ) ;
/* FIXME interlacing min height is 6 */
if ( crtc_w < 3 | | crtc_h < 3 )
visible = false ;
if ( src_w < 3 | | src_h < 3 )
visible = false ;
width_bytes = ( ( src_x * pixel_size ) & 63 ) + src_w * pixel_size ;
if ( src_w > 2048 | | src_h > 2048 | |
width_bytes > 4096 | | fb - > pitches [ 0 ] > 4096 ) {
DRM_DEBUG_KMS ( " Source dimensions exceed hardware limits \n " ) ;
return - EINVAL ;
}
}
dst . x1 = crtc_x ;
dst . x2 = crtc_x + crtc_w ;
dst . y1 = crtc_y ;
dst . y2 = crtc_y + crtc_h ;
2011-12-13 13:19:38 -08:00
/*
* If the sprite is completely covering the primary plane ,
* we can disable the primary and save power .
*/
2014-04-29 13:35:47 +03:00
primary_enabled = ! drm_rect_equals ( & dst , & clip ) | | colorkey_enabled ( intel_plane ) ;
WARN_ON ( ! primary_enabled & & ! visible & & intel_crtc - > active ) ;
2011-12-13 13:19:38 -08:00
mutex_lock ( & dev - > struct_mutex ) ;
2013-03-05 14:52:39 +00:00
/* Note that this will apply the VT-d workaround for scanouts,
* which is more restrictive than required for sprites . ( The
* primary plane requires 256 KiB alignment with 64 PTE padding ,
* the sprite planes only require 128 KiB alignment and 32 PTE padding .
*/
2011-12-13 13:19:38 -08:00
ret = intel_pin_and_fence_fb_obj ( dev , obj , NULL ) ;
2013-10-01 18:02:12 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2012-01-13 15:48:39 -08:00
if ( ret )
2013-10-01 18:02:12 +03:00
return ret ;
2011-12-13 13:19:38 -08:00
2013-10-01 18:02:15 +03:00
intel_plane - > crtc_x = orig . crtc_x ;
intel_plane - > crtc_y = orig . crtc_y ;
intel_plane - > crtc_w = orig . crtc_w ;
intel_plane - > crtc_h = orig . crtc_h ;
intel_plane - > src_x = orig . src_x ;
intel_plane - > src_y = orig . src_y ;
intel_plane - > src_w = orig . src_w ;
intel_plane - > src_h = orig . src_h ;
2011-12-13 13:19:38 -08:00
intel_plane - > obj = obj ;
2013-10-01 18:02:11 +03:00
if ( intel_crtc - > active ) {
2014-04-29 13:35:47 +03:00
bool primary_was_enabled = intel_crtc - > primary_enabled ;
intel_crtc - > primary_enabled = primary_enabled ;
if ( primary_was_enabled & & ! primary_enabled )
intel_pre_disable_primary ( crtc ) ;
2013-10-01 18:02:11 +03:00
if ( visible )
intel_plane - > update_plane ( plane , crtc , fb , obj ,
crtc_x , crtc_y , crtc_w , crtc_h ,
src_x , src_y , src_w , src_h ) ;
else
intel_plane - > disable_plane ( plane , crtc ) ;
2014-04-29 13:35:47 +03:00
if ( ! primary_was_enabled & & primary_enabled )
intel_post_enable_primary ( crtc ) ;
2013-10-01 18:02:11 +03:00
}
2011-12-13 13:19:39 -08:00
2011-12-13 13:19:38 -08:00
/* Unpin old obj after new one is active to avoid ugliness */
if ( old_obj ) {
/*
* It ' s fairly common to simply update the position of
* an existing object . In that case , we don ' t need to
* wait for vblank to avoid ugliness , we only need to
* do the pin & ref bookkeeping .
*/
2013-10-01 18:02:12 +03:00
if ( old_obj ! = obj & & intel_crtc - > active )
2013-10-01 18:02:14 +03:00
intel_wait_for_vblank ( dev , intel_crtc - > pipe ) ;
2013-10-01 18:02:12 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-12-14 13:57:08 +01:00
intel_unpin_fb_obj ( old_obj ) ;
2013-10-01 18:02:12 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2011-12-13 13:19:38 -08:00
}
2013-10-01 18:02:12 +03:00
return 0 ;
2011-12-13 13:19:38 -08:00
}
static int
intel_disable_plane ( struct drm_plane * plane )
{
struct drm_device * dev = plane - > dev ;
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2013-10-01 18:02:11 +03:00
struct intel_crtc * intel_crtc ;
2011-12-13 13:19:38 -08:00
2013-08-07 13:30:23 +03:00
if ( ! plane - > fb )
return 0 ;
if ( WARN_ON ( ! plane - > crtc ) )
return - EINVAL ;
2013-10-01 18:02:11 +03:00
intel_crtc = to_intel_crtc ( plane - > crtc ) ;
if ( intel_crtc - > active ) {
2014-04-29 13:35:47 +03:00
bool primary_was_enabled = intel_crtc - > primary_enabled ;
intel_crtc - > primary_enabled = true ;
2013-10-01 18:02:11 +03:00
intel_plane - > disable_plane ( plane , plane - > crtc ) ;
2014-04-29 13:35:47 +03:00
if ( ! primary_was_enabled & & intel_crtc - > primary_enabled )
intel_post_enable_primary ( plane - > crtc ) ;
2013-10-01 18:02:11 +03:00
}
2011-12-13 13:19:38 -08:00
2013-10-01 18:02:13 +03:00
if ( intel_plane - > obj ) {
if ( intel_crtc - > active )
intel_wait_for_vblank ( dev , intel_plane - > pipe ) ;
2013-03-27 17:49:13 +02:00
2013-10-01 18:02:13 +03:00
mutex_lock ( & dev - > struct_mutex ) ;
intel_unpin_fb_obj ( intel_plane - > obj ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
2013-10-01 18:02:12 +03:00
2013-10-01 18:02:13 +03:00
intel_plane - > obj = NULL ;
}
2011-12-13 13:19:38 -08:00
2013-10-01 18:02:13 +03:00
return 0 ;
2011-12-13 13:19:38 -08:00
}
static void intel_destroy_plane ( struct drm_plane * plane )
{
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
intel_disable_plane ( plane ) ;
drm_plane_cleanup ( plane ) ;
kfree ( intel_plane ) ;
}
2012-01-03 08:05:39 -08:00
int intel_sprite_set_colorkey ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct drm_intel_sprite_colorkey * set = data ;
struct drm_mode_object * obj ;
struct drm_plane * plane ;
struct intel_plane * intel_plane ;
int ret = 0 ;
2012-04-24 09:55:08 +02:00
if ( ! drm_core_check_feature ( dev , DRIVER_MODESET ) )
return - ENODEV ;
2012-01-03 08:05:39 -08:00
/* Make sure we don't try to enable both src & dest simultaneously */
if ( ( set - > flags & ( I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE ) ) = = ( I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE ) )
return - EINVAL ;
2012-12-02 01:05:46 +01:00
drm_modeset_lock_all ( dev ) ;
2012-01-03 08:05:39 -08:00
obj = drm_mode_object_find ( dev , set - > plane_id , DRM_MODE_OBJECT_PLANE ) ;
if ( ! obj ) {
2013-10-17 13:35:03 +03:00
ret = - ENOENT ;
2012-01-03 08:05:39 -08:00
goto out_unlock ;
}
plane = obj_to_plane ( obj ) ;
intel_plane = to_intel_plane ( plane ) ;
ret = intel_plane - > update_colorkey ( plane , set ) ;
out_unlock :
2012-12-02 01:05:46 +01:00
drm_modeset_unlock_all ( dev ) ;
2012-01-03 08:05:39 -08:00
return ret ;
}
int intel_sprite_get_colorkey ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct drm_intel_sprite_colorkey * get = data ;
struct drm_mode_object * obj ;
struct drm_plane * plane ;
struct intel_plane * intel_plane ;
int ret = 0 ;
2012-04-24 09:55:08 +02:00
if ( ! drm_core_check_feature ( dev , DRIVER_MODESET ) )
return - ENODEV ;
2012-01-03 08:05:39 -08:00
2012-12-02 01:05:46 +01:00
drm_modeset_lock_all ( dev ) ;
2012-01-03 08:05:39 -08:00
obj = drm_mode_object_find ( dev , get - > plane_id , DRM_MODE_OBJECT_PLANE ) ;
if ( ! obj ) {
2013-10-17 13:35:03 +03:00
ret = - ENOENT ;
2012-01-03 08:05:39 -08:00
goto out_unlock ;
}
plane = obj_to_plane ( obj ) ;
intel_plane = to_intel_plane ( plane ) ;
intel_plane - > get_colorkey ( plane , get ) ;
out_unlock :
2012-12-02 01:05:46 +01:00
drm_modeset_unlock_all ( dev ) ;
2012-01-03 08:05:39 -08:00
return ret ;
}
2013-03-26 09:25:43 -07:00
void intel_plane_restore ( struct drm_plane * plane )
{
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
if ( ! plane - > crtc | | ! plane - > fb )
return ;
intel_update_plane ( plane , plane - > crtc , plane - > fb ,
intel_plane - > crtc_x , intel_plane - > crtc_y ,
intel_plane - > crtc_w , intel_plane - > crtc_h ,
intel_plane - > src_x , intel_plane - > src_y ,
intel_plane - > src_w , intel_plane - > src_h ) ;
}
2013-06-04 13:49:04 +03:00
void intel_plane_disable ( struct drm_plane * plane )
{
if ( ! plane - > crtc | | ! plane - > fb )
return ;
intel_disable_plane ( plane ) ;
}
2011-12-13 13:19:38 -08:00
static const struct drm_plane_funcs intel_plane_funcs = {
. update_plane = intel_update_plane ,
. disable_plane = intel_disable_plane ,
. destroy = intel_destroy_plane ,
} ;
2012-04-10 11:41:49 +01:00
static uint32_t ilk_plane_formats [ ] = {
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
} ;
2011-12-13 13:19:38 -08:00
static uint32_t snb_plane_formats [ ] = {
DRM_FORMAT_XBGR8888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
} ;
2013-04-02 11:22:20 -07:00
static uint32_t vlv_plane_formats [ ] = {
DRM_FORMAT_RGB565 ,
DRM_FORMAT_ABGR8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XBGR8888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_XBGR2101010 ,
DRM_FORMAT_ABGR2101010 ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
} ;
2011-12-13 13:19:38 -08:00
int
2013-04-02 11:22:20 -07:00
intel_plane_init ( struct drm_device * dev , enum pipe pipe , int plane )
2011-12-13 13:19:38 -08:00
{
struct intel_plane * intel_plane ;
unsigned long possible_crtcs ;
2012-04-10 11:41:49 +01:00
const uint32_t * plane_formats ;
int num_plane_formats ;
2011-12-13 13:19:38 -08:00
int ret ;
2012-04-10 11:41:49 +01:00
if ( INTEL_INFO ( dev ) - > gen < 5 )
2011-12-13 13:19:38 -08:00
return - ENODEV ;
2013-09-19 12:18:32 +02:00
intel_plane = kzalloc ( sizeof ( * intel_plane ) , GFP_KERNEL ) ;
2011-12-13 13:19:38 -08:00
if ( ! intel_plane )
return - ENOMEM ;
2012-04-10 11:41:49 +01:00
switch ( INTEL_INFO ( dev ) - > gen ) {
case 5 :
case 6 :
2012-10-22 18:19:27 +01:00
intel_plane - > can_scale = true ;
2011-12-13 13:19:38 -08:00
intel_plane - > max_downscale = 16 ;
2012-04-10 11:41:49 +01:00
intel_plane - > update_plane = ilk_update_plane ;
intel_plane - > disable_plane = ilk_disable_plane ;
intel_plane - > update_colorkey = ilk_update_colorkey ;
intel_plane - > get_colorkey = ilk_get_colorkey ;
if ( IS_GEN6 ( dev ) ) {
plane_formats = snb_plane_formats ;
num_plane_formats = ARRAY_SIZE ( snb_plane_formats ) ;
} else {
plane_formats = ilk_plane_formats ;
num_plane_formats = ARRAY_SIZE ( ilk_plane_formats ) ;
}
break ;
case 7 :
2013-11-02 21:07:07 -07:00
case 8 :
2013-04-25 15:15:00 +01:00
if ( IS_IVYBRIDGE ( dev ) ) {
2012-10-22 18:19:27 +01:00
intel_plane - > can_scale = true ;
2013-04-25 15:15:00 +01:00
intel_plane - > max_downscale = 2 ;
} else {
intel_plane - > can_scale = false ;
intel_plane - > max_downscale = 1 ;
}
2013-04-02 11:22:20 -07:00
if ( IS_VALLEYVIEW ( dev ) ) {
intel_plane - > update_plane = vlv_update_plane ;
intel_plane - > disable_plane = vlv_disable_plane ;
intel_plane - > update_colorkey = vlv_update_colorkey ;
intel_plane - > get_colorkey = vlv_get_colorkey ;
plane_formats = vlv_plane_formats ;
num_plane_formats = ARRAY_SIZE ( vlv_plane_formats ) ;
} else {
intel_plane - > update_plane = ivb_update_plane ;
intel_plane - > disable_plane = ivb_disable_plane ;
intel_plane - > update_colorkey = ivb_update_colorkey ;
intel_plane - > get_colorkey = ivb_get_colorkey ;
plane_formats = snb_plane_formats ;
num_plane_formats = ARRAY_SIZE ( snb_plane_formats ) ;
}
2012-04-10 11:41:49 +01:00
break ;
default :
2012-06-27 00:55:37 +02:00
kfree ( intel_plane ) ;
2012-04-10 11:41:49 +01:00
return - ENODEV ;
2011-12-13 13:19:38 -08:00
}
intel_plane - > pipe = pipe ;
2013-04-02 11:22:20 -07:00
intel_plane - > plane = plane ;
2011-12-13 13:19:38 -08:00
possible_crtcs = ( 1 < < pipe ) ;
ret = drm_plane_init ( dev , & intel_plane - > base , possible_crtcs ,
2012-04-10 11:41:49 +01:00
& intel_plane_funcs ,
plane_formats , num_plane_formats ,
false ) ;
2011-12-13 13:19:38 -08:00
if ( ret )
kfree ( intel_plane ) ;
return ret ;
}