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>
2015-04-15 15:15:02 -07:00
# include <drm/drm_atomic.h>
2014-12-23 10:41:52 -08:00
# include <drm/drm_plane_helper.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-10-20 19:47:53 +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 ;
}
}
2015-09-25 16:37:43 +03:00
static int usecs_to_scanlines ( const struct drm_display_mode * adjusted_mode ,
int usecs )
2014-04-29 13:35:46 +03:00
{
/* paranoia */
2015-09-25 16:37:43 +03:00
if ( ! adjusted_mode - > crtc_htotal )
2014-04-29 13:35:46 +03:00
return 1 ;
2015-09-25 16:37:43 +03:00
return DIV_ROUND_UP ( usecs * adjusted_mode - > crtc_clock ,
1000 * adjusted_mode - > crtc_htotal ) ;
2014-04-29 13:35:46 +03:00
}
2014-10-28 15:10:12 +02:00
/**
* intel_pipe_update_start ( ) - start update of a set of display registers
* @ crtc : the crtc of which the registers are going to be updated
* @ start_vbl_count : vblank counter return pointer used for error checking
*
* Mark the start of an update to pipe registers that should be updated
* atomically regarding vblank . If the next vblank will happens within
* the next 100 us , this function waits until the vblank passes .
*
* After a successful call to this function , interrupts will be disabled
* until a subsequent call to intel_pipe_update_end ( ) . That is done to
* avoid random delays . The value written to @ start_vbl_count should be
* supplied to intel_pipe_update_end ( ) for error checking .
*/
2015-08-31 13:04:25 +02:00
void intel_pipe_update_start ( struct intel_crtc * crtc )
2014-04-29 13:35:46 +03:00
{
struct drm_device * dev = crtc - > base . dev ;
2015-09-08 13:40:45 +03:00
const struct drm_display_mode * adjusted_mode = & crtc - > config - > base . adjusted_mode ;
2014-04-29 13:35:46 +03:00
enum pipe pipe = crtc - > pipe ;
long timeout = msecs_to_jiffies_timeout ( 1 ) ;
int scanline , min , max , vblank_start ;
2014-05-22 19:00:50 +03:00
wait_queue_head_t * wq = drm_crtc_vblank_waitqueue ( & crtc - > base ) ;
2014-04-29 13:35:46 +03:00
DEFINE_WAIT ( wait ) ;
2015-09-08 13:40:45 +03:00
vblank_start = adjusted_mode - > crtc_vblank_start ;
if ( adjusted_mode - > flags & DRM_MODE_FLAG_INTERLACE )
2014-04-29 13:35:46 +03:00
vblank_start = DIV_ROUND_UP ( vblank_start , 2 ) ;
/* FIXME needs to be calibrated sensibly */
2015-09-08 13:40:45 +03:00
min = vblank_start - usecs_to_scanlines ( adjusted_mode , 100 ) ;
2014-04-29 13:35:46 +03:00
max = vblank_start - 1 ;
2015-07-13 16:30:32 +02:00
local_irq_disable ( ) ;
2014-04-29 13:35:46 +03:00
if ( min < = 0 | | max < = 0 )
2015-07-13 16:30:32 +02:00
return ;
2014-04-29 13:35:46 +03:00
2015-02-13 21:03:45 +01:00
if ( WARN_ON ( drm_crtc_vblank_get ( & crtc - > base ) ) )
2015-07-13 16:30:32 +02:00
return ;
2014-04-29 13:35:46 +03:00
2015-09-17 08:08:32 -07:00
crtc - > debug . min_vbl = min ;
crtc - > debug . max_vbl = max ;
trace_i915_pipe_update_start ( crtc ) ;
2014-04-29 13:35:48 +03:00
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 .
*/
2014-05-22 19:00:50 +03:00
prepare_to_wait ( wq , & wait , TASK_UNINTERRUPTIBLE ) ;
2014-04-29 13:35:46 +03:00
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 ( ) ;
}
2014-05-22 19:00:50 +03:00
finish_wait ( wq , & wait ) ;
2014-04-29 13:35:46 +03:00
2015-02-13 21:03:45 +01:00
drm_crtc_vblank_put ( & crtc - > base ) ;
2014-04-29 13:35:46 +03:00
2015-09-15 14:19:32 -07:00
crtc - > debug . scanline_start = scanline ;
crtc - > debug . start_vbl_time = ktime_get ( ) ;
crtc - > debug . start_vbl_count =
dev - > driver - > get_vblank_counter ( dev , pipe ) ;
2014-04-29 13:35:46 +03:00
2015-09-17 08:08:32 -07:00
trace_i915_pipe_update_vblank_evaded ( crtc ) ;
2014-04-29 13:35:46 +03:00
}
2014-10-28 15:10:12 +02:00
/**
* intel_pipe_update_end ( ) - end update of a set of display registers
* @ crtc : the crtc of which the registers were updated
* @ start_vbl_count : start vblank counter ( used for error checking )
*
* Mark the end of an update started with intel_pipe_update_start ( ) . This
* re - enables interrupts and verifies the update was actually completed
* before a vblank using the value of @ start_vbl_count .
*/
2015-08-31 13:04:25 +02:00
void intel_pipe_update_end ( struct intel_crtc * crtc )
2014-04-29 13:35:46 +03:00
{
struct drm_device * dev = crtc - > base . dev ;
enum pipe pipe = crtc - > pipe ;
2015-09-15 14:19:32 -07:00
int scanline_end = intel_get_crtc_scanline ( crtc ) ;
2014-04-29 13:35:46 +03:00
u32 end_vbl_count = dev - > driver - > get_vblank_counter ( dev , pipe ) ;
2015-09-01 12:15:33 +02:00
ktime_t end_vbl_time = ktime_get ( ) ;
2014-04-29 13:35:46 +03:00
2015-09-17 08:08:32 -07:00
trace_i915_pipe_update_end ( crtc , end_vbl_count , scanline_end ) ;
2014-04-29 13:35:48 +03:00
2014-04-29 13:35:46 +03:00
local_irq_enable ( ) ;
2015-09-15 14:19:32 -07:00
if ( crtc - > debug . start_vbl_count & &
crtc - > debug . start_vbl_count ! = end_vbl_count ) {
DRM_ERROR ( " Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d \n " ,
pipe_name ( pipe ) , crtc - > debug . start_vbl_count ,
end_vbl_count ,
ktime_us_delta ( end_vbl_time , crtc - > debug . start_vbl_time ) ,
crtc - > debug . min_vbl , crtc - > debug . max_vbl ,
crtc - > debug . scanline_start , scanline_end ) ;
}
2014-04-29 13:35:46 +03:00
}
2013-12-04 00:49:41 +00:00
static void
skl_update_plane ( struct drm_plane * drm_plane , struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
2015-03-19 17:57:11 +02:00
int crtc_x , int crtc_y ,
2013-12-04 00:49:41 +00:00
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 = drm_plane - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_plane * intel_plane = to_intel_plane ( drm_plane ) ;
2015-03-19 17:57:11 +02:00
struct drm_i915_gem_object * obj = intel_fb_obj ( fb ) ;
2013-12-04 00:49:41 +00:00
const int pipe = intel_plane - > pipe ;
const int plane = intel_plane - > plane + 1 ;
2015-04-10 14:37:29 +05:30
u32 plane_ctl , stride_div , stride ;
2015-10-09 18:22:43 -03:00
int pixel_size = drm_format_plane_cpp ( fb - > pixel_format , 0 ) ;
2015-06-15 12:33:54 +02:00
const struct drm_intel_sprite_colorkey * key =
& to_intel_plane_state ( drm_plane - > state ) - > ckey ;
2015-03-23 11:10:37 +00:00
unsigned long surf_addr ;
2015-04-10 14:37:29 +05:30
u32 tile_height , plane_offset , plane_size ;
unsigned int rotation ;
int x_offset , y_offset ;
2015-04-15 15:15:02 -07:00
struct intel_crtc_state * crtc_state = to_intel_crtc ( crtc ) - > config ;
int scaler_id ;
2013-12-04 00:49:41 +00:00
2015-03-19 17:57:13 +02:00
plane_ctl = PLANE_CTL_ENABLE |
PLANE_CTL_PIPE_CSC_ENABLE ;
2013-12-04 00:49:41 +00:00
2015-04-15 15:15:02 -07:00
plane_ctl | = skl_plane_ctl_format ( fb - > pixel_format ) ;
plane_ctl | = skl_plane_ctl_tiling ( fb - > modifier [ 0 ] ) ;
2015-02-27 11:15:18 +00:00
2015-04-10 14:37:29 +05:30
rotation = drm_plane - > state - > rotation ;
2015-04-15 15:15:02 -07:00
plane_ctl | = skl_plane_ctl_rotation ( rotation ) ;
2013-12-04 00:49:41 +00:00
2015-10-09 18:22:43 -03:00
intel_update_sprite_watermarks ( drm_plane , crtc , src_w , src_h ,
pixel_size , true ,
src_w ! = crtc_w | | src_h ! = crtc_h ) ;
2015-02-27 11:15:18 +00:00
stride_div = intel_fb_stride_alignment ( dev , fb - > modifier [ 0 ] ,
fb - > pixel_format ) ;
2015-04-15 15:15:02 -07:00
scaler_id = to_intel_plane_state ( drm_plane - > state ) - > scaler_id ;
2013-12-04 00:49:41 +00:00
/* Sizes are 0 based */
src_w - - ;
src_h - - ;
crtc_w - - ;
crtc_h - - ;
2015-03-19 21:18:57 +02:00
if ( key - > flags ) {
I915_WRITE ( PLANE_KEYVAL ( pipe , plane ) , key - > min_value ) ;
I915_WRITE ( PLANE_KEYMAX ( pipe , plane ) , key - > max_value ) ;
I915_WRITE ( PLANE_KEYMSK ( pipe , plane ) , key - > channel_mask ) ;
}
if ( key - > flags & I915_SET_COLORKEY_DESTINATION )
plane_ctl | = PLANE_CTL_KEY_ENABLE_DESTINATION ;
else if ( key - > flags & I915_SET_COLORKEY_SOURCE )
plane_ctl | = PLANE_CTL_KEY_ENABLE_SOURCE ;
2015-09-21 10:45:35 +01:00
surf_addr = intel_plane_obj_offset ( intel_plane , obj , 0 ) ;
2015-03-23 11:10:37 +00:00
2015-04-10 14:37:29 +05:30
if ( intel_rotation_90_or_270 ( rotation ) ) {
/* stride: Surface height in tiles */
2015-05-08 20:22:46 -07:00
tile_height = intel_tile_height ( dev , fb - > pixel_format ,
2015-09-21 10:45:32 +01:00
fb - > modifier [ 0 ] , 0 ) ;
2015-04-10 14:37:29 +05:30
stride = DIV_ROUND_UP ( fb - > height , tile_height ) ;
plane_size = ( src_w < < 16 ) | src_h ;
x_offset = stride * tile_height - y - ( src_h + 1 ) ;
y_offset = x ;
} else {
stride = fb - > pitches [ 0 ] / stride_div ;
plane_size = ( src_h < < 16 ) | src_w ;
x_offset = x ;
y_offset = y ;
}
plane_offset = y_offset < < 16 | x_offset ;
I915_WRITE ( PLANE_OFFSET ( pipe , plane ) , plane_offset ) ;
I915_WRITE ( PLANE_STRIDE ( pipe , plane ) , stride ) ;
I915_WRITE ( PLANE_SIZE ( pipe , plane ) , plane_size ) ;
2015-04-15 15:15:02 -07:00
/* program plane scaler */
if ( scaler_id > = 0 ) {
uint32_t ps_ctrl = 0 ;
DRM_DEBUG_KMS ( " plane = %d PS_PLANE_SEL(plane) = 0x%x \n " , plane ,
PS_PLANE_SEL ( plane ) ) ;
ps_ctrl = PS_SCALER_EN | PS_PLANE_SEL ( plane ) |
crtc_state - > scaler_state . scalers [ scaler_id ] . mode ;
I915_WRITE ( SKL_PS_CTRL ( pipe , scaler_id ) , ps_ctrl ) ;
I915_WRITE ( SKL_PS_PWR_GATE ( pipe , scaler_id ) , 0 ) ;
I915_WRITE ( SKL_PS_WIN_POS ( pipe , scaler_id ) , ( crtc_x < < 16 ) | crtc_y ) ;
I915_WRITE ( SKL_PS_WIN_SZ ( pipe , scaler_id ) ,
( ( crtc_w + 1 ) < < 16 ) | ( crtc_h + 1 ) ) ;
I915_WRITE ( PLANE_POS ( pipe , plane ) , 0 ) ;
} else {
I915_WRITE ( PLANE_POS ( pipe , plane ) , ( crtc_y < < 16 ) | crtc_x ) ;
}
2013-12-04 00:49:41 +00:00
I915_WRITE ( PLANE_CTL ( pipe , plane ) , plane_ctl ) ;
2015-03-23 11:10:37 +00:00
I915_WRITE ( PLANE_SURF ( pipe , plane ) , surf_addr ) ;
2013-12-04 00:49:41 +00:00
POSTING_READ ( PLANE_SURF ( pipe , plane ) ) ;
}
static void
2015-06-15 12:33:47 +02:00
skl_disable_plane ( struct drm_plane * dplane , struct drm_crtc * crtc )
2013-12-04 00:49:41 +00:00
{
2015-04-21 17:12:51 +03:00
struct drm_device * dev = dplane - > dev ;
2013-12-04 00:49:41 +00:00
struct drm_i915_private * dev_priv = dev - > dev_private ;
2015-04-21 17:12:51 +03:00
struct intel_plane * intel_plane = to_intel_plane ( dplane ) ;
2013-12-04 00:49:41 +00:00
const int pipe = intel_plane - > pipe ;
const int plane = intel_plane - > plane + 1 ;
2015-03-19 17:57:13 +02:00
I915_WRITE ( PLANE_CTL ( pipe , plane ) , 0 ) ;
2013-12-04 00:49:41 +00:00
2015-03-19 17:57:14 +02:00
I915_WRITE ( PLANE_SURF ( pipe , plane ) , 0 ) ;
POSTING_READ ( PLANE_SURF ( pipe , plane ) ) ;
2015-10-09 18:22:43 -03:00
intel_update_sprite_watermarks ( dplane , crtc , 0 , 0 , 0 , false , false ) ;
2013-12-04 00:49:41 +00:00
}
2014-10-20 19:47:53 +03:00
static void
chv_update_csc ( struct intel_plane * intel_plane , uint32_t format )
{
struct drm_i915_private * dev_priv = intel_plane - > base . dev - > dev_private ;
int plane = intel_plane - > plane ;
/* Seems RGB data bypasses the CSC always */
if ( ! format_is_yuv ( format ) )
return ;
/*
* BT .601 limited range YCbCr - > full range RGB
*
* | r | | 6537 4769 0 | | cr |
* | g | = | - 3330 4769 - 1605 | x | y - 64 |
* | b | | 0 4769 8263 | | cb |
*
* Cb and Cr apparently come in as signed already , so no
* need for any offset . For Y we need to remove the offset .
*/
I915_WRITE ( SPCSCYGOFF ( plane ) , SPCSC_OOFF ( 0 ) | SPCSC_IOFF ( - 64 ) ) ;
I915_WRITE ( SPCSCCBOFF ( plane ) , SPCSC_OOFF ( 0 ) | SPCSC_IOFF ( 0 ) ) ;
I915_WRITE ( SPCSCCROFF ( plane ) , SPCSC_OOFF ( 0 ) | SPCSC_IOFF ( 0 ) ) ;
I915_WRITE ( SPCSCC01 ( plane ) , SPCSC_C1 ( 4769 ) | SPCSC_C0 ( 6537 ) ) ;
I915_WRITE ( SPCSCC23 ( plane ) , SPCSC_C1 ( - 3330 ) | SPCSC_C0 ( 0 ) ) ;
I915_WRITE ( SPCSCC45 ( plane ) , SPCSC_C1 ( - 1605 ) | SPCSC_C0 ( 4769 ) ) ;
I915_WRITE ( SPCSCC67 ( plane ) , SPCSC_C1 ( 4769 ) | SPCSC_C0 ( 0 ) ) ;
I915_WRITE ( SPCSCC8 ( plane ) , SPCSC_C0 ( 8263 ) ) ;
I915_WRITE ( SPCSCYGICLAMP ( plane ) , SPCSC_IMAX ( 940 ) | SPCSC_IMIN ( 64 ) ) ;
I915_WRITE ( SPCSCCBICLAMP ( plane ) , SPCSC_IMAX ( 448 ) | SPCSC_IMIN ( - 448 ) ) ;
I915_WRITE ( SPCSCCRICLAMP ( plane ) , SPCSC_IMAX ( 448 ) | SPCSC_IMIN ( - 448 ) ) ;
I915_WRITE ( SPCSCYGOCLAMP ( plane ) , SPCSC_OMAX ( 1023 ) | SPCSC_OMIN ( 0 ) ) ;
I915_WRITE ( SPCSCCBOCLAMP ( plane ) , SPCSC_OMAX ( 1023 ) | SPCSC_OMIN ( 0 ) ) ;
I915_WRITE ( SPCSCCROCLAMP ( plane ) , SPCSC_OMAX ( 1023 ) | SPCSC_OMIN ( 0 ) ) ;
}
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 ,
2015-03-19 17:57:11 +02:00
int crtc_x , int crtc_y ,
2013-04-02 11:22:20 -07:00
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 ) ;
2015-03-19 17:57:11 +02:00
struct drm_i915_gem_object * obj = intel_fb_obj ( fb ) ;
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 ) ;
2015-06-15 12:33:54 +02:00
const struct drm_intel_sprite_colorkey * key =
& to_intel_plane_state ( dplane - > state ) - > ckey ;
2013-04-02 11:22:20 -07:00
2015-03-19 17:57:13 +02:00
sprctl = SP_ENABLE ;
2013-04-02 11:22:20 -07:00
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 ;
/* Sizes are 0 based */
src_w - - ;
src_h - - ;
crtc_w - - ;
crtc_h - - ;
linear_offset = y * fb - > pitches [ 0 ] + x * pixel_size ;
2015-06-11 16:31:14 +03:00
sprsurf_offset = intel_gen4_compute_page_offset ( dev_priv ,
& x , & y ,
2013-04-02 11:22:20 -07:00
obj - > tiling_mode ,
pixel_size ,
fb - > pitches [ 0 ] ) ;
linear_offset - = sprsurf_offset ;
2015-01-21 16:35:41 -08:00
if ( dplane - > state - > rotation = = BIT ( DRM_ROTATE_180 ) ) {
2014-08-05 11:26:52 +05:30
sprctl | = SP_ROTATE_180 ;
x + = src_w ;
y + = src_h ;
linear_offset + = src_h * fb - > pitches [ 0 ] + src_w * pixel_size ;
}
2015-03-19 21:18:57 +02:00
if ( key - > flags ) {
I915_WRITE ( SPKEYMINVAL ( pipe , plane ) , key - > min_value ) ;
I915_WRITE ( SPKEYMAXVAL ( pipe , plane ) , key - > max_value ) ;
I915_WRITE ( SPKEYMSK ( pipe , plane ) , key - > channel_mask ) ;
}
if ( key - > flags & I915_SET_COLORKEY_SOURCE )
sprctl | = SP_SOURCE_KEY ;
2014-10-20 19:47:53 +03:00
if ( IS_CHERRYVIEW ( dev ) & & pipe = = PIPE_B )
chv_update_csc ( intel_plane , fb - > pixel_format ) ;
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 ) ;
2014-10-16 20:52:34 +03:00
I915_WRITE ( SPCONSTALPHA ( pipe , plane ) , 0 ) ;
2013-04-02 11:22:20 -07:00
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 ) ;
2015-05-26 20:27:23 +03:00
POSTING_READ ( SPSURF ( pipe , plane ) ) ;
2013-04-02 11:22:20 -07:00
}
static void
2015-06-15 12:33:47 +02: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 ) ;
int pipe = intel_plane - > pipe ;
int plane = intel_plane - > plane ;
2015-03-19 17:57:13 +02:00
I915_WRITE ( SPCNTR ( pipe , plane ) , 0 ) ;
2014-01-24 10:31:44 +01:00
I915_WRITE ( SPSURF ( pipe , plane ) , 0 ) ;
2015-05-26 20:27:23 +03:00
POSTING_READ ( SPSURF ( pipe , plane ) ) ;
2013-04-02 11:22:20 -07:00
}
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 ,
2015-03-19 17:57:11 +02:00
int crtc_x , int crtc_y ,
2011-12-13 13:19:38 -08:00
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 ) ;
2015-03-19 17:57:11 +02:00
struct drm_i915_gem_object * obj = intel_fb_obj ( fb ) ;
2015-03-19 21:18:57 +02:00
enum pipe pipe = intel_plane - > pipe ;
2011-12-13 13:19:38 -08:00
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 ) ;
2015-06-15 12:33:54 +02:00
const struct drm_intel_sprite_colorkey * key =
& to_intel_plane_state ( plane - > state ) - > ckey ;
2011-12-13 13:19:38 -08:00
2015-03-19 17:57:13 +02:00
sprctl = SPRITE_ENABLE ;
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 ;
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 ;
2015-10-09 18:22:43 -03:00
intel_update_sprite_watermarks ( plane , crtc , src_w , src_h , pixel_size ,
true ,
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 =
2015-06-11 16:31:14 +03:00
intel_gen4_compute_page_offset ( dev_priv ,
& x , & y , obj - > tiling_mode ,
2013-02-21 20:04:31 +00:00
pixel_size , fb - > pitches [ 0 ] ) ;
2012-10-26 18:20:12 +01:00
linear_offset - = sprsurf_offset ;
2015-01-21 16:35:41 -08:00
if ( plane - > state - > rotation = = BIT ( DRM_ROTATE_180 ) ) {
2014-08-05 11:26:52 +05:30
sprctl | = SPRITE_ROTATE_180 ;
/* HSW and BDW does this automagically in hardware */
if ( ! IS_HASWELL ( dev ) & & ! IS_BROADWELL ( dev ) ) {
x + = src_w ;
y + = src_h ;
linear_offset + = src_h * fb - > pitches [ 0 ] +
src_w * pixel_size ;
}
}
2015-03-19 21:18:57 +02:00
if ( key - > flags ) {
I915_WRITE ( SPRKEYVAL ( pipe ) , key - > min_value ) ;
I915_WRITE ( SPRKEYMAX ( pipe ) , key - > max_value ) ;
I915_WRITE ( SPRKEYMSK ( pipe ) , key - > channel_mask ) ;
}
if ( key - > flags & I915_SET_COLORKEY_DESTINATION )
sprctl | = SPRITE_DEST_KEY ;
else if ( key - > flags & I915_SET_COLORKEY_SOURCE )
sprctl | = SPRITE_SOURCE_KEY ;
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 ) ;
2015-05-26 20:27:23 +03:00
POSTING_READ ( SPRSURF ( pipe ) ) ;
2011-12-13 13:19:38 -08:00
}
static void
2015-06-15 12:33:47 +02: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 ) ;
int pipe = intel_plane - > pipe ;
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 ) ;
2014-04-29 13:35:47 +03:00
2015-05-26 20:27:23 +03:00
I915_WRITE ( SPRSURF ( pipe ) , 0 ) ;
POSTING_READ ( SPRSURF ( pipe ) ) ;
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 ,
2015-03-19 17:57:11 +02:00
int crtc_x , int crtc_y ,
2011-12-13 13:19:38 -08:00
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 ) ;
2015-03-19 17:57:11 +02:00
struct drm_i915_gem_object * obj = intel_fb_obj ( fb ) ;
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 ) ;
2015-06-15 12:33:54 +02:00
const struct drm_intel_sprite_colorkey * key =
& to_intel_plane_state ( plane - > state ) - > ckey ;
2011-12-13 13:19:38 -08:00
2015-03-19 17:57:13 +02:00
dvscntr = DVS_ENABLE ;
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
2015-10-09 18:22:43 -03:00
intel_update_sprite_watermarks ( plane , crtc , src_w , src_h ,
pixel_size , true ,
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 =
2015-06-11 16:31:14 +03:00
intel_gen4_compute_page_offset ( dev_priv ,
& x , & y , obj - > tiling_mode ,
2013-02-21 20:04:31 +00:00
pixel_size , fb - > pitches [ 0 ] ) ;
2012-10-26 18:20:12 +01:00
linear_offset - = dvssurf_offset ;
2015-01-21 16:35:41 -08:00
if ( plane - > state - > rotation = = BIT ( DRM_ROTATE_180 ) ) {
2014-08-05 11:26:52 +05:30
dvscntr | = DVS_ROTATE_180 ;
x + = src_w ;
y + = src_h ;
linear_offset + = src_h * fb - > pitches [ 0 ] + src_w * pixel_size ;
}
2015-03-19 21:18:57 +02:00
if ( key - > flags ) {
I915_WRITE ( DVSKEYVAL ( pipe ) , key - > min_value ) ;
I915_WRITE ( DVSKEYMAX ( pipe ) , key - > max_value ) ;
I915_WRITE ( DVSKEYMSK ( pipe ) , key - > channel_mask ) ;
}
if ( key - > flags & I915_SET_COLORKEY_DESTINATION )
dvscntr | = DVS_DEST_KEY ;
else if ( key - > flags & I915_SET_COLORKEY_SOURCE )
dvscntr | = DVS_SOURCE_KEY ;
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 ) ;
2015-05-26 20:27:23 +03:00
POSTING_READ ( DVSSURF ( pipe ) ) ;
2011-12-13 13:19:38 -08:00
}
static void
2015-06-15 12:33:47 +02: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 ) ;
int pipe = intel_plane - > pipe ;
2015-03-19 17:57:13 +02:00
I915_WRITE ( DVSCNTR ( pipe ) , 0 ) ;
2011-12-13 13:19:38 -08:00
/* Disable the scaler */
I915_WRITE ( DVSSCALE ( pipe ) , 0 ) ;
2015-03-19 17:57:13 +02:00
2014-01-24 10:31:44 +01:00
I915_WRITE ( DVSSURF ( pipe ) , 0 ) ;
2015-05-26 20:27:23 +03:00
POSTING_READ ( DVSSURF ( pipe ) ) ;
2011-12-13 13:19:38 -08:00
}
static int
2014-09-05 17:04:47 -03:00
intel_check_sprite_plane ( struct drm_plane * plane ,
2015-06-15 12:33:46 +02:00
struct intel_crtc_state * crtc_state ,
2014-09-05 17:04:47 -03:00
struct intel_plane_state * state )
2011-12-13 13:19:38 -08:00
{
2015-04-15 15:15:02 -07:00
struct drm_device * dev = plane - > dev ;
2015-06-15 12:33:46 +02:00
struct drm_crtc * crtc = state - > base . crtc ;
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
2011-12-13 13:19:38 -08:00
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2014-12-01 15:40:13 -08:00
struct drm_framebuffer * fb = state - > base . fb ;
2014-09-05 17:04:47 -03:00
int crtc_x , crtc_y ;
unsigned int crtc_w , crtc_h ;
uint32_t src_x , src_y , src_w , src_h ;
struct drm_rect * src = & state - > src ;
struct drm_rect * dst = & state - > dst ;
const struct drm_rect * clip = & state - > clip ;
2013-04-24 18:52:38 +03:00
int hscale , vscale ;
int max_scale , min_scale ;
2015-05-18 16:18:44 -07:00
bool can_scale ;
2014-12-04 10:27:42 -08:00
int pixel_size ;
if ( ! fb ) {
state - > visible = false ;
2015-06-15 12:33:44 +02:00
return 0 ;
2014-12-04 10:27:42 -08:00
}
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
2015-05-18 16:18:44 -07:00
/* setup can_scale, min_scale, max_scale */
if ( INTEL_INFO ( dev ) - > gen > = 9 ) {
/* use scaler when colorkey is not required */
2015-06-15 12:33:54 +02:00
if ( state - > ckey . flags = = I915_SET_COLORKEY_NONE ) {
2015-05-18 16:18:44 -07:00
can_scale = 1 ;
min_scale = 1 ;
max_scale = skl_max_scale ( intel_crtc , crtc_state ) ;
} else {
can_scale = 0 ;
min_scale = DRM_PLANE_HELPER_NO_SCALING ;
max_scale = DRM_PLANE_HELPER_NO_SCALING ;
}
} else {
can_scale = intel_plane - > can_scale ;
max_scale = intel_plane - > max_downscale < < 16 ;
min_scale = intel_plane - > can_scale ? 1 : ( 1 < < 16 ) ;
}
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 .
*/
2014-09-05 17:04:47 -03:00
drm_rect_rotate ( src , fb - > width < < 16 , fb - > height < < 16 ,
2015-01-21 16:35:41 -08:00
state - > base . rotation ) ;
2014-08-05 11:26:52 +05:30
2014-09-05 17:04:47 -03:00
hscale = drm_rect_calc_hscale_relaxed ( src , dst , min_scale , max_scale ) ;
2013-04-24 18:52:39 +03:00
BUG_ON ( hscale < 0 ) ;
2013-04-24 18:52:38 +03:00
2014-09-05 17:04:47 -03:00
vscale = drm_rect_calc_vscale_relaxed ( src , dst , min_scale , max_scale ) ;
2013-04-24 18:52:39 +03:00
BUG_ON ( vscale < 0 ) ;
2011-12-13 13:19:38 -08:00
2015-06-15 12:33:54 +02:00
state - > visible = drm_rect_clip_scaled ( src , dst , clip , hscale , vscale ) ;
2011-12-13 13:19:38 -08:00
2014-09-05 17:04:47 -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
2014-09-05 17:04:47 -03:00
if ( state - > visible ) {
2013-04-24 18:52:39 +03:00
/* check again in case clipping clamped the results */
2014-09-05 17:04:47 -03:00
hscale = drm_rect_calc_hscale ( src , dst , min_scale , max_scale ) ;
2013-04-24 18:52:39 +03:00
if ( hscale < 0 ) {
DRM_DEBUG_KMS ( " Horizontal scaling factor out of limits \n " ) ;
2014-09-05 17:04:47 -03:00
drm_rect_debug_print ( src , true ) ;
drm_rect_debug_print ( dst , false ) ;
2013-04-24 18:52:39 +03:00
return hscale ;
}
2014-09-05 17:04:47 -03:00
vscale = drm_rect_calc_vscale ( src , dst , min_scale , max_scale ) ;
2013-04-24 18:52:39 +03:00
if ( vscale < 0 ) {
DRM_DEBUG_KMS ( " Vertical scaling factor out of limits \n " ) ;
2014-09-05 17:04:47 -03:00
drm_rect_debug_print ( src , true ) ;
drm_rect_debug_print ( dst , false ) ;
2013-04-24 18:52:39 +03:00
return vscale ;
}
2013-04-24 18:52:38 +03:00
/* Make the source viewport size an exact multiple of the scaling factors. */
2014-09-05 17:04:47 -03:00
drm_rect_adjust_size ( src ,
drm_rect_width ( dst ) * hscale - drm_rect_width ( src ) ,
drm_rect_height ( dst ) * vscale - drm_rect_height ( src ) ) ;
2013-04-24 18:52:38 +03:00
2014-09-05 17:04:47 -03:00
drm_rect_rotate_inv ( src , fb - > width < < 16 , fb - > height < < 16 ,
2015-01-21 16:35:41 -08:00
state - > base . rotation ) ;
2014-08-05 11:26:52 +05:30
2013-04-24 18:52:38 +03:00
/* sanity check to make sure the src viewport wasn't enlarged */
2014-12-23 10:41:52 -08:00
WARN_ON ( src - > x1 < ( int ) state - > base . src_x | |
src - > y1 < ( int ) state - > base . src_y | |
src - > x2 > ( int ) state - > base . src_x + state - > base . src_w | |
src - > y2 > ( int ) state - > base . src_y + state - > base . src_h ) ;
2013-04-24 18:52:38 +03:00
/*
* 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 .
*/
2014-09-05 17:04:47 -03:00
src_x = src - > x1 > > 16 ;
src_w = drm_rect_width ( src ) > > 16 ;
src_y = src - > y1 > > 16 ;
src_h = drm_rect_height ( src ) > > 16 ;
2013-04-24 18:52:38 +03:00
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 .
*/
2015-05-18 16:18:44 -07:00
if ( ! can_scale )
2013-04-24 18:52:38 +03:00
crtc_w & = ~ 1 ;
if ( crtc_w = = 0 )
2014-09-05 17:04:47 -03:00
state - > visible = false ;
2013-04-24 18:52:38 +03:00
}
}
/* Check size restrictions when scaling */
2014-09-05 17:04:47 -03:00
if ( state - > visible & & ( src_w ! = crtc_w | | src_h ! = crtc_h ) ) {
2013-04-24 18:52:38 +03:00
unsigned int width_bytes ;
2015-05-18 16:18:44 -07:00
WARN_ON ( ! can_scale ) ;
2013-04-24 18:52:38 +03:00
/* FIXME interlacing min height is 6 */
if ( crtc_w < 3 | | crtc_h < 3 )
2014-09-05 17:04:47 -03:00
state - > visible = false ;
2013-04-24 18:52:38 +03:00
if ( src_w < 3 | | src_h < 3 )
2014-09-05 17:04:47 -03:00
state - > visible = false ;
2013-04-24 18:52:38 +03:00
2014-12-04 10:27:42 -08:00
pixel_size = drm_format_plane_cpp ( fb - > pixel_format , 0 ) ;
2014-09-05 17:04:47 -03:00
width_bytes = ( ( src_x * pixel_size ) & 63 ) +
src_w * pixel_size ;
2013-04-24 18:52:38 +03:00
2015-04-15 15:15:02 -07:00
if ( INTEL_INFO ( dev ) - > gen < 9 & & ( src_w > 2048 | | src_h > 2048 | |
width_bytes > 4096 | | fb - > pitches [ 0 ] > 4096 ) ) {
2013-04-24 18:52:38 +03:00
DRM_DEBUG_KMS ( " Source dimensions exceed hardware limits \n " ) ;
return - EINVAL ;
}
}
2014-09-05 17:04:47 -03:00
if ( state - > visible ) {
2015-04-09 16:41:54 -07:00
src - > x1 = src_x < < 16 ;
src - > x2 = ( src_x + src_w ) < < 16 ;
src - > y1 = src_y < < 16 ;
src - > y2 = ( src_y + src_h ) < < 16 ;
2014-09-05 17:04:47 -03:00
}
dst - > x1 = crtc_x ;
dst - > x2 = crtc_x + crtc_w ;
dst - > y1 = crtc_y ;
dst - > y2 = crtc_y + crtc_h ;
return 0 ;
}
2014-10-24 14:51:32 +01:00
static void
intel_commit_sprite_plane ( struct drm_plane * plane ,
struct intel_plane_state * state )
{
2014-12-01 15:40:13 -08:00
struct drm_crtc * crtc = state - > base . crtc ;
2014-10-24 14:51:32 +01:00
struct intel_plane * intel_plane = to_intel_plane ( plane ) ;
2014-12-01 15:40:13 -08:00
struct drm_framebuffer * fb = state - > base . fb ;
2014-10-24 14:51:32 +01:00
2014-12-23 10:41:52 -08:00
crtc = crtc ? crtc : plane - > crtc ;
2015-06-15 12:33:52 +02:00
if ( ! crtc - > state - > active )
2015-06-15 12:33:45 +02:00
return ;
if ( state - > visible ) {
intel_plane - > update_plane ( plane , crtc , fb ,
state - > dst . x1 , state - > dst . y1 ,
drm_rect_width ( & state - > dst ) ,
drm_rect_height ( & state - > dst ) ,
state - > src . x1 > > 16 ,
state - > src . y1 > > 16 ,
drm_rect_width ( & state - > src ) > > 16 ,
drm_rect_height ( & state - > src ) > > 16 ) ;
} else {
2015-06-15 12:33:47 +02:00
intel_plane - > disable_plane ( plane , crtc ) ;
2013-10-01 18:02:11 +03:00
}
2011-12-13 13:19:38 -08:00
}
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_plane * plane ;
2015-06-15 12:33:54 +02:00
struct drm_plane_state * plane_state ;
struct drm_atomic_state * state ;
struct drm_modeset_acquire_ctx ctx ;
2012-01-03 08:05:39 -08:00
int ret = 0 ;
/* 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 ;
2015-03-19 21:18:57 +02:00
if ( IS_VALLEYVIEW ( dev ) & &
set - > flags & I915_SET_COLORKEY_DESTINATION )
return - EINVAL ;
2014-07-17 23:30:04 -04:00
plane = drm_plane_find ( dev , set - > plane_id ) ;
2015-06-15 12:33:54 +02:00
if ( ! plane | | plane - > type ! = DRM_PLANE_TYPE_OVERLAY )
return - ENOENT ;
2012-01-03 08:05:39 -08:00
2015-06-15 12:33:54 +02:00
drm_modeset_acquire_init ( & ctx , 0 ) ;
2015-04-27 13:48:39 -07:00
2015-06-15 12:33:54 +02:00
state = drm_atomic_state_alloc ( plane - > dev ) ;
if ( ! state ) {
ret = - ENOMEM ;
goto out ;
2015-04-27 13:48:39 -07:00
}
2015-06-15 12:33:54 +02:00
state - > acquire_ctx = & ctx ;
while ( 1 ) {
plane_state = drm_atomic_get_plane_state ( state , plane ) ;
ret = PTR_ERR_OR_ZERO ( plane_state ) ;
if ( ! ret ) {
to_intel_plane_state ( plane_state ) - > ckey = * set ;
ret = drm_atomic_commit ( state ) ;
}
2015-04-27 13:48:39 -07:00
2015-06-15 12:33:54 +02:00
if ( ret ! = - EDEADLK )
break ;
2012-01-03 08:05:39 -08:00
2015-06-15 12:33:54 +02:00
drm_atomic_state_clear ( state ) ;
drm_modeset_backoff ( & ctx ) ;
}
2012-01-03 08:05:39 -08:00
2015-06-15 12:33:54 +02:00
if ( ret )
drm_atomic_state_free ( state ) ;
2013-03-26 09:25:43 -07:00
2015-06-15 12:33:54 +02:00
out :
drm_modeset_drop_locks ( & ctx ) ;
drm_modeset_acquire_fini ( & ctx ) ;
return ret ;
2013-03-26 09:25:43 -07:00
}
2015-05-12 16:13:22 +01:00
static const uint32_t ilk_plane_formats [ ] = {
2012-04-10 11:41:49 +01:00
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
} ;
2015-05-12 16:13:22 +01:00
static const uint32_t snb_plane_formats [ ] = {
2011-12-13 13:19:38 -08:00
DRM_FORMAT_XBGR8888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
} ;
2015-05-12 16:13:22 +01:00
static const uint32_t vlv_plane_formats [ ] = {
2013-04-02 11:22:20 -07:00
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 ,
} ;
2013-12-04 00:49:41 +00:00
static uint32_t skl_plane_formats [ ] = {
DRM_FORMAT_RGB565 ,
DRM_FORMAT_ABGR8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XBGR8888 ,
DRM_FORMAT_XRGB8888 ,
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 ;
2015-01-21 16:35:41 -08:00
struct intel_plane_state * state ;
2011-12-13 13:19:38 -08:00
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 ;
2015-01-21 16:35:41 -08:00
state = intel_create_plane_state ( & intel_plane - > base ) ;
if ( ! state ) {
2014-12-23 10:41:52 -08:00
kfree ( intel_plane ) ;
return - ENOMEM ;
}
2015-01-21 16:35:41 -08:00
intel_plane - > base . state = & state - > base ;
2014-12-23 10:41:52 -08:00
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 ;
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 ;
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 ;
plane_formats = snb_plane_formats ;
num_plane_formats = ARRAY_SIZE ( snb_plane_formats ) ;
}
2012-04-10 11:41:49 +01:00
break ;
2013-12-04 00:49:41 +00:00
case 9 :
2015-04-15 15:15:02 -07:00
intel_plane - > can_scale = true ;
2013-12-04 00:49:41 +00:00
intel_plane - > update_plane = skl_update_plane ;
intel_plane - > disable_plane = skl_disable_plane ;
2015-04-07 15:28:38 -07:00
state - > scaler_id = - 1 ;
2013-12-04 00:49:41 +00:00
plane_formats = skl_plane_formats ;
num_plane_formats = ARRAY_SIZE ( skl_plane_formats ) ;
break ;
2012-04-10 11:41:49 +01:00
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 ;
2015-09-14 21:35:42 +05:30
intel_plane - > frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE ( pipe , plane ) ;
2014-12-01 15:40:16 -08:00
intel_plane - > check_plane = intel_check_sprite_plane ;
intel_plane - > commit_plane = intel_commit_sprite_plane ;
2011-12-13 13:19:38 -08:00
possible_crtcs = ( 1 < < pipe ) ;
2014-09-03 10:38:20 -03:00
ret = drm_universal_plane_init ( dev , & intel_plane - > base , possible_crtcs ,
2015-01-21 16:35:42 -08:00
& intel_plane_funcs ,
2014-09-03 10:38:20 -03:00
plane_formats , num_plane_formats ,
DRM_PLANE_TYPE_OVERLAY ) ;
2014-08-05 11:26:55 +05:30
if ( ret ) {
2011-12-13 13:19:38 -08:00
kfree ( intel_plane ) ;
2014-08-05 11:26:55 +05:30
goto out ;
}
2015-04-10 14:37:29 +05:30
intel_create_rotation_property ( dev , intel_plane ) ;
2011-12-13 13:19:38 -08:00
2014-12-23 10:41:52 -08:00
drm_plane_helper_add ( & intel_plane - > base , & intel_plane_helper_funcs ) ;
2015-06-04 16:56:18 +01:00
out :
2011-12-13 13:19:38 -08:00
return ret ;
}