2009-06-05 16:42:42 +04:00
/*
* Copyright 2007 - 8 Advanced Micro Devices , Inc .
* Copyright 2008 Red Hat Inc .
*
* 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 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 COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) 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 : Dave Airlie
* Alex Deucher
*/
# include <drm/drmP.h>
# include <drm/drm_crtc_helper.h>
# include <drm/radeon_drm.h>
# include "radeon_fixed.h"
# include "radeon.h"
2009-08-13 10:32:14 +04:00
# include "atom.h"
2009-06-05 16:42:42 +04:00
2009-12-04 18:40:41 +03:00
static void radeon_overscan_setup ( struct drm_crtc * crtc ,
struct drm_display_mode * mode )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
WREG32 ( RADEON_OVR_CLR + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( RADEON_OVR_WID_LEFT_RIGHT + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( RADEON_OVR_WID_TOP_BOTTOM + radeon_crtc - > crtc_offset , 0 ) ;
}
2009-07-13 23:04:08 +04:00
static void radeon_legacy_rmx_mode_set ( struct drm_crtc * crtc ,
2009-12-17 09:24:59 +03:00
struct drm_display_mode * mode )
2009-07-13 23:04:08 +04:00
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
int xres = mode - > hdisplay ;
int yres = mode - > vdisplay ;
bool hscale = true , vscale = true ;
int hsync_wid ;
int vsync_wid ;
int hsync_start ;
int blank_width ;
u32 scale , inc , crtc_more_cntl ;
u32 fp_horz_stretch , fp_vert_stretch , fp_horz_vert_active ;
u32 fp_h_sync_strt_wid , fp_crtc_h_total_disp ;
u32 fp_v_sync_strt_wid , fp_crtc_v_total_disp ;
2009-10-09 23:14:30 +04:00
struct drm_display_mode * native_mode = & radeon_crtc - > native_mode ;
2009-07-13 23:04:08 +04:00
fp_vert_stretch = RREG32 ( RADEON_FP_VERT_STRETCH ) &
( RADEON_VERT_STRETCH_RESERVED |
RADEON_VERT_AUTO_RATIO_INC ) ;
fp_horz_stretch = RREG32 ( RADEON_FP_HORZ_STRETCH ) &
( RADEON_HORZ_FP_LOOP_STRETCH |
RADEON_HORZ_AUTO_RATIO_INC ) ;
crtc_more_cntl = 0 ;
if ( ( rdev - > family = = CHIP_RS100 ) | |
( rdev - > family = = CHIP_RS200 ) ) {
/* This is to workaround the asic bug for RMX, some versions
of BIOS dosen ' t have this register initialized correctly . */
crtc_more_cntl | = RADEON_CRTC_H_CUTOFF_ACTIVE_EN ;
}
fp_crtc_h_total_disp = ( ( ( ( mode - > crtc_htotal / 8 ) - 1 ) & 0x3ff )
| ( ( ( ( mode - > crtc_hdisplay / 8 ) - 1 ) & 0x1ff ) < < 16 ) ) ;
hsync_wid = ( mode - > crtc_hsync_end - mode - > crtc_hsync_start ) / 8 ;
if ( ! hsync_wid )
hsync_wid = 1 ;
hsync_start = mode - > crtc_hsync_start - 8 ;
fp_h_sync_strt_wid = ( ( hsync_start & 0x1fff )
| ( ( hsync_wid & 0x3f ) < < 16 )
| ( ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
? RADEON_CRTC_H_SYNC_POL
: 0 ) ) ;
fp_crtc_v_total_disp = ( ( ( mode - > crtc_vtotal - 1 ) & 0xffff )
| ( ( mode - > crtc_vdisplay - 1 ) < < 16 ) ) ;
vsync_wid = mode - > crtc_vsync_end - mode - > crtc_vsync_start ;
if ( ! vsync_wid )
vsync_wid = 1 ;
fp_v_sync_strt_wid = ( ( ( mode - > crtc_vsync_start - 1 ) & 0xfff )
| ( ( vsync_wid & 0x1f ) < < 16 )
| ( ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
? RADEON_CRTC_V_SYNC_POL
: 0 ) ) ;
fp_horz_vert_active = 0 ;
2009-10-09 23:14:30 +04:00
if ( native_mode - > hdisplay = = 0 | |
native_mode - > vdisplay = = 0 ) {
2009-07-13 23:04:08 +04:00
hscale = false ;
vscale = false ;
} else {
2009-10-09 23:14:30 +04:00
if ( xres > native_mode - > hdisplay )
xres = native_mode - > hdisplay ;
if ( yres > native_mode - > vdisplay )
yres = native_mode - > vdisplay ;
2009-07-13 23:04:08 +04:00
2009-10-09 23:14:30 +04:00
if ( xres = = native_mode - > hdisplay )
2009-07-13 23:04:08 +04:00
hscale = false ;
2009-10-09 23:14:30 +04:00
if ( yres = = native_mode - > vdisplay )
2009-07-13 23:04:08 +04:00
vscale = false ;
}
switch ( radeon_crtc - > rmx_type ) {
case RMX_FULL :
case RMX_ASPECT :
if ( ! hscale )
fp_horz_stretch | = ( ( xres / 8 - 1 ) < < 16 ) ;
else {
inc = ( fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC ) ? 1 : 0 ;
scale = ( ( xres + inc ) * RADEON_HORZ_STRETCH_RATIO_MAX )
2009-10-09 23:14:30 +04:00
/ native_mode - > hdisplay + 1 ;
2009-07-13 23:04:08 +04:00
fp_horz_stretch | = ( ( ( scale ) & RADEON_HORZ_STRETCH_RATIO_MASK ) |
RADEON_HORZ_STRETCH_BLEND |
RADEON_HORZ_STRETCH_ENABLE |
2009-10-09 23:14:30 +04:00
( ( native_mode - > hdisplay / 8 - 1 ) < < 16 ) ) ;
2009-07-13 23:04:08 +04:00
}
if ( ! vscale )
fp_vert_stretch | = ( ( yres - 1 ) < < 12 ) ;
else {
inc = ( fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC ) ? 1 : 0 ;
scale = ( ( yres + inc ) * RADEON_VERT_STRETCH_RATIO_MAX )
2009-10-09 23:14:30 +04:00
/ native_mode - > vdisplay + 1 ;
2009-07-13 23:04:08 +04:00
fp_vert_stretch | = ( ( ( scale ) & RADEON_VERT_STRETCH_RATIO_MASK ) |
RADEON_VERT_STRETCH_ENABLE |
RADEON_VERT_STRETCH_BLEND |
2009-10-09 23:14:30 +04:00
( ( native_mode - > vdisplay - 1 ) < < 12 ) ) ;
2009-07-13 23:04:08 +04:00
}
break ;
case RMX_CENTER :
fp_horz_stretch | = ( ( xres / 8 - 1 ) < < 16 ) ;
fp_vert_stretch | = ( ( yres - 1 ) < < 12 ) ;
crtc_more_cntl | = ( RADEON_CRTC_AUTO_HORZ_CENTER_EN |
RADEON_CRTC_AUTO_VERT_CENTER_EN ) ;
blank_width = ( mode - > crtc_hblank_end - mode - > crtc_hblank_start ) / 8 ;
if ( blank_width > 110 )
blank_width = 110 ;
fp_crtc_h_total_disp = ( ( ( blank_width ) & 0x3ff )
| ( ( ( ( mode - > crtc_hdisplay / 8 ) - 1 ) & 0x1ff ) < < 16 ) ) ;
hsync_wid = ( mode - > crtc_hsync_end - mode - > crtc_hsync_start ) / 8 ;
if ( ! hsync_wid )
hsync_wid = 1 ;
fp_h_sync_strt_wid = ( ( ( ( mode - > crtc_hsync_start - mode - > crtc_hblank_start ) / 8 ) & 0x1fff )
| ( ( hsync_wid & 0x3f ) < < 16 )
| ( ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
? RADEON_CRTC_H_SYNC_POL
: 0 ) ) ;
fp_crtc_v_total_disp = ( ( ( mode - > crtc_vblank_end - mode - > crtc_vblank_start ) & 0xffff )
| ( ( mode - > crtc_vdisplay - 1 ) < < 16 ) ) ;
vsync_wid = mode - > crtc_vsync_end - mode - > crtc_vsync_start ;
if ( ! vsync_wid )
vsync_wid = 1 ;
fp_v_sync_strt_wid = ( ( ( ( mode - > crtc_vsync_start - mode - > crtc_vblank_start ) & 0xfff )
| ( ( vsync_wid & 0x1f ) < < 16 )
| ( ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
? RADEON_CRTC_V_SYNC_POL
: 0 ) ) ) ;
2009-10-09 23:14:30 +04:00
fp_horz_vert_active = ( ( ( native_mode - > vdisplay ) & 0xfff ) |
( ( ( native_mode - > hdisplay / 8 ) & 0x1ff ) < < 16 ) ) ;
2009-07-13 23:04:08 +04:00
break ;
case RMX_OFF :
default :
fp_horz_stretch | = ( ( xres / 8 - 1 ) < < 16 ) ;
fp_vert_stretch | = ( ( yres - 1 ) < < 12 ) ;
break ;
}
WREG32 ( RADEON_FP_HORZ_STRETCH , fp_horz_stretch ) ;
WREG32 ( RADEON_FP_VERT_STRETCH , fp_vert_stretch ) ;
WREG32 ( RADEON_CRTC_MORE_CNTL , crtc_more_cntl ) ;
WREG32 ( RADEON_FP_HORZ_VERT_ACTIVE , fp_horz_vert_active ) ;
WREG32 ( RADEON_FP_H_SYNC_STRT_WID , fp_h_sync_strt_wid ) ;
WREG32 ( RADEON_FP_V_SYNC_STRT_WID , fp_v_sync_strt_wid ) ;
WREG32 ( RADEON_FP_CRTC_H_TOTAL_DISP , fp_crtc_h_total_disp ) ;
WREG32 ( RADEON_FP_CRTC_V_TOTAL_DISP , fp_crtc_v_total_disp ) ;
}
2009-06-05 16:42:42 +04:00
void radeon_restore_common_regs ( struct drm_device * dev )
{
/* don't need this yet */
}
static void radeon_pll_wait_for_read_update_complete ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
int i = 0 ;
/* FIXME: Certain revisions of R300 can't recover here. Not sure of
the cause yet , but this workaround will mask the problem for now .
Other chips usually will pass at the very first test , so the
workaround shouldn ' t have any effect on them . */
for ( i = 0 ;
( i < 10000 & &
RREG32_PLL ( RADEON_PPLL_REF_DIV ) & RADEON_PPLL_ATOMIC_UPDATE_R ) ;
i + + ) ;
}
static void radeon_pll_write_update ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
while ( RREG32_PLL ( RADEON_PPLL_REF_DIV ) & RADEON_PPLL_ATOMIC_UPDATE_R ) ;
WREG32_PLL_P ( RADEON_PPLL_REF_DIV ,
RADEON_PPLL_ATOMIC_UPDATE_W ,
~ ( RADEON_PPLL_ATOMIC_UPDATE_W ) ) ;
}
static void radeon_pll2_wait_for_read_update_complete ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
int i = 0 ;
/* FIXME: Certain revisions of R300 can't recover here. Not sure of
the cause yet , but this workaround will mask the problem for now .
Other chips usually will pass at the very first test , so the
workaround shouldn ' t have any effect on them . */
for ( i = 0 ;
( i < 10000 & &
RREG32_PLL ( RADEON_P2PLL_REF_DIV ) & RADEON_P2PLL_ATOMIC_UPDATE_R ) ;
i + + ) ;
}
static void radeon_pll2_write_update ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
while ( RREG32_PLL ( RADEON_P2PLL_REF_DIV ) & RADEON_P2PLL_ATOMIC_UPDATE_R ) ;
WREG32_PLL_P ( RADEON_P2PLL_REF_DIV ,
RADEON_P2PLL_ATOMIC_UPDATE_W ,
~ ( RADEON_P2PLL_ATOMIC_UPDATE_W ) ) ;
}
static uint8_t radeon_compute_pll_gain ( uint16_t ref_freq , uint16_t ref_div ,
uint16_t fb_div )
{
unsigned int vcoFreq ;
if ( ! ref_div )
return 1 ;
vcoFreq = ( ( unsigned ) ref_freq & fb_div ) / ref_div ;
/*
* This is horribly crude : the VCO frequency range is divided into
* 3 parts , each part having a fixed PLL gain value .
*/
if ( vcoFreq > = 30000 )
/*
* [ 300. . max ] MHz : 7
*/
return 7 ;
else if ( vcoFreq > = 18000 )
/*
* [ 180. .300 ) MHz : 4
*/
return 4 ;
else
/*
* [ 0. .180 ) MHz : 1
*/
return 1 ;
}
void radeon_crtc_dpms ( struct drm_crtc * crtc , int mode )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
uint32_t mask ;
if ( radeon_crtc - > crtc_id )
2009-12-03 20:15:54 +03:00
mask = ( RADEON_CRTC2_DISP_DIS |
2009-06-05 16:42:42 +04:00
RADEON_CRTC2_VSYNC_DIS |
RADEON_CRTC2_HSYNC_DIS |
RADEON_CRTC2_DISP_REQ_EN_B ) ;
else
mask = ( RADEON_CRTC_DISPLAY_DIS |
RADEON_CRTC_VSYNC_DIS |
RADEON_CRTC_HSYNC_DIS ) ;
switch ( mode ) {
case DRM_MODE_DPMS_ON :
if ( radeon_crtc - > crtc_id )
2009-12-03 20:15:54 +03:00
WREG32_P ( RADEON_CRTC2_GEN_CNTL , RADEON_CRTC2_EN , ~ ( RADEON_CRTC2_EN | mask ) ) ;
2009-06-05 16:42:42 +04:00
else {
WREG32_P ( RADEON_CRTC_GEN_CNTL , RADEON_CRTC_EN , ~ ( RADEON_CRTC_EN |
RADEON_CRTC_DISP_REQ_EN_B ) ) ;
WREG32_P ( RADEON_CRTC_EXT_CNTL , 0 , ~ mask ) ;
}
2009-08-13 13:10:51 +04:00
drm_vblank_post_modeset ( dev , radeon_crtc - > crtc_id ) ;
radeon_crtc_load_lut ( crtc ) ;
2009-06-05 16:42:42 +04:00
break ;
case DRM_MODE_DPMS_STANDBY :
case DRM_MODE_DPMS_SUSPEND :
case DRM_MODE_DPMS_OFF :
2009-08-13 13:10:51 +04:00
drm_vblank_pre_modeset ( dev , radeon_crtc - > crtc_id ) ;
2009-06-05 16:42:42 +04:00
if ( radeon_crtc - > crtc_id )
2009-12-03 20:15:54 +03:00
WREG32_P ( RADEON_CRTC2_GEN_CNTL , mask , ~ ( RADEON_CRTC2_EN | mask ) ) ;
2009-06-05 16:42:42 +04:00
else {
WREG32_P ( RADEON_CRTC_GEN_CNTL , RADEON_CRTC_DISP_REQ_EN_B , ~ ( RADEON_CRTC_EN |
RADEON_CRTC_DISP_REQ_EN_B ) ) ;
WREG32_P ( RADEON_CRTC_EXT_CNTL , mask , ~ mask ) ;
}
break ;
}
}
int radeon_crtc_set_base ( struct drm_crtc * crtc , int x , int y ,
struct drm_framebuffer * old_fb )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct radeon_framebuffer * radeon_fb ;
struct drm_gem_object * obj ;
2009-11-20 16:29:23 +03:00
struct radeon_bo * rbo ;
2009-06-05 16:42:42 +04:00
uint64_t base ;
uint32_t crtc_offset , crtc_offset_cntl , crtc_tile_x0_y0 = 0 ;
uint32_t crtc_pitch , pitch_pixels ;
2009-06-24 03:48:08 +04:00
uint32_t tiling_flags ;
2009-09-16 04:15:21 +04:00
int format ;
uint32_t gen_cntl_reg , gen_cntl_val ;
2009-11-20 16:29:23 +03:00
int r ;
2009-06-05 16:42:42 +04:00
DRM_DEBUG ( " \n " ) ;
2009-11-18 01:08:55 +03:00
/* no fb bound */
if ( ! crtc - > fb ) {
DRM_DEBUG ( " No FB bound \n " ) ;
return 0 ;
}
2009-06-05 16:42:42 +04:00
radeon_fb = to_radeon_framebuffer ( crtc - > fb ) ;
2009-09-16 04:15:21 +04:00
switch ( crtc - > fb - > bits_per_pixel ) {
case 8 :
format = 2 ;
break ;
case 15 : /* 555 */
format = 3 ;
break ;
case 16 : /* 565 */
format = 4 ;
break ;
case 24 : /* RGB */
format = 5 ;
break ;
case 32 : /* xRGB */
format = 6 ;
break ;
default :
return false ;
}
2009-11-20 16:29:23 +03:00
/* Pin framebuffer & get tilling informations */
2009-06-05 16:42:42 +04:00
obj = radeon_fb - > obj ;
2009-11-20 16:29:23 +03:00
rbo = obj - > driver_private ;
r = radeon_bo_reserve ( rbo , false ) ;
if ( unlikely ( r ! = 0 ) )
return r ;
r = radeon_bo_pin ( rbo , RADEON_GEM_DOMAIN_VRAM , & base ) ;
if ( unlikely ( r ! = 0 ) ) {
radeon_bo_unreserve ( rbo ) ;
2009-06-05 16:42:42 +04:00
return - EINVAL ;
}
2009-11-20 16:29:23 +03:00
radeon_bo_get_tiling_flags ( rbo , & tiling_flags , NULL ) ;
radeon_bo_unreserve ( rbo ) ;
if ( tiling_flags & RADEON_TILING_MICRO )
DRM_ERROR ( " trying to scanout microtiled buffer \n " ) ;
2009-07-09 09:04:19 +04:00
/* if scanout was in GTT this really wouldn't work */
/* crtc offset is from display base addr not FB location */
radeon_crtc - > legacy_display_base_addr = rdev - > mc . vram_location ;
base - = radeon_crtc - > legacy_display_base_addr ;
2009-06-05 16:42:42 +04:00
crtc_offset_cntl = 0 ;
pitch_pixels = crtc - > fb - > pitch / ( crtc - > fb - > bits_per_pixel / 8 ) ;
crtc_pitch = ( ( ( pitch_pixels * crtc - > fb - > bits_per_pixel ) +
( ( crtc - > fb - > bits_per_pixel * 8 ) - 1 ) ) /
( crtc - > fb - > bits_per_pixel * 8 ) ) ;
crtc_pitch | = crtc_pitch < < 16 ;
2009-06-24 03:48:08 +04:00
if ( tiling_flags & RADEON_TILING_MACRO ) {
2009-06-05 16:42:42 +04:00
if ( ASIC_IS_R300 ( rdev ) )
crtc_offset_cntl | = ( R300_CRTC_X_Y_MODE_EN |
R300_CRTC_MICRO_TILE_BUFFER_DIS |
R300_CRTC_MACRO_TILE_EN ) ;
else
crtc_offset_cntl | = RADEON_CRTC_TILE_EN ;
} else {
if ( ASIC_IS_R300 ( rdev ) )
crtc_offset_cntl & = ~ ( R300_CRTC_X_Y_MODE_EN |
R300_CRTC_MICRO_TILE_BUFFER_DIS |
R300_CRTC_MACRO_TILE_EN ) ;
else
crtc_offset_cntl & = ~ RADEON_CRTC_TILE_EN ;
}
2009-06-24 03:48:08 +04:00
if ( tiling_flags & RADEON_TILING_MACRO ) {
2009-06-05 16:42:42 +04:00
if ( ASIC_IS_R300 ( rdev ) ) {
crtc_tile_x0_y0 = x | ( y < < 16 ) ;
base & = ~ 0x7ff ;
} else {
int byteshift = crtc - > fb - > bits_per_pixel > > 4 ;
2009-06-24 03:48:08 +04:00
int tile_addr = ( ( ( y > > 3 ) * pitch_pixels + x ) > > ( 8 - byteshift ) ) < < 11 ;
2009-06-05 16:42:42 +04:00
base + = tile_addr + ( ( x < < byteshift ) % 256 ) + ( ( y % 8 ) < < 8 ) ;
crtc_offset_cntl | = ( y % 16 ) ;
}
} else {
int offset = y * pitch_pixels + x ;
switch ( crtc - > fb - > bits_per_pixel ) {
2009-09-16 04:15:21 +04:00
case 8 :
offset * = 1 ;
break ;
2009-06-05 16:42:42 +04:00
case 15 :
case 16 :
offset * = 2 ;
break ;
case 24 :
offset * = 3 ;
break ;
case 32 :
offset * = 4 ;
break ;
default :
return false ;
}
base + = offset ;
}
base & = ~ 7 ;
2009-09-16 04:15:21 +04:00
if ( radeon_crtc - > crtc_id = = 1 )
gen_cntl_reg = RADEON_CRTC2_GEN_CNTL ;
else
gen_cntl_reg = RADEON_CRTC_GEN_CNTL ;
gen_cntl_val = RREG32 ( gen_cntl_reg ) ;
gen_cntl_val & = ~ ( 0xf < < 8 ) ;
gen_cntl_val | = ( format < < 8 ) ;
WREG32 ( gen_cntl_reg , gen_cntl_val ) ;
2009-06-05 16:42:42 +04:00
crtc_offset = ( u32 ) base ;
2009-07-09 09:04:19 +04:00
WREG32 ( RADEON_DISPLAY_BASE_ADDR + radeon_crtc - > crtc_offset , radeon_crtc - > legacy_display_base_addr ) ;
2009-06-05 16:42:42 +04:00
if ( ASIC_IS_R300 ( rdev ) ) {
if ( radeon_crtc - > crtc_id )
WREG32 ( R300_CRTC2_TILE_X0_Y0 , crtc_tile_x0_y0 ) ;
else
WREG32 ( R300_CRTC_TILE_X0_Y0 , crtc_tile_x0_y0 ) ;
}
WREG32 ( RADEON_CRTC_OFFSET_CNTL + radeon_crtc - > crtc_offset , crtc_offset_cntl ) ;
WREG32 ( RADEON_CRTC_OFFSET + radeon_crtc - > crtc_offset , crtc_offset ) ;
WREG32 ( RADEON_CRTC_PITCH + radeon_crtc - > crtc_offset , crtc_pitch ) ;
if ( old_fb & & old_fb ! = crtc - > fb ) {
radeon_fb = to_radeon_framebuffer ( old_fb ) ;
2009-11-20 16:29:23 +03:00
rbo = radeon_fb - > obj - > driver_private ;
r = radeon_bo_reserve ( rbo , false ) ;
if ( unlikely ( r ! = 0 ) )
return r ;
radeon_bo_unpin ( rbo ) ;
radeon_bo_unreserve ( rbo ) ;
2009-06-05 16:42:42 +04:00
}
2009-10-08 12:44:09 +04:00
/* Bytes per pixel may have changed */
radeon_bandwidth_update ( rdev ) ;
2009-06-05 16:42:42 +04:00
return 0 ;
}
static bool radeon_set_crtc_timing ( struct drm_crtc * crtc , struct drm_display_mode * mode )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
2009-08-13 10:32:14 +04:00
struct drm_encoder * encoder ;
2009-06-05 16:42:42 +04:00
int format ;
int hsync_start ;
int hsync_wid ;
int vsync_wid ;
uint32_t crtc_h_total_disp ;
uint32_t crtc_h_sync_strt_wid ;
uint32_t crtc_v_total_disp ;
uint32_t crtc_v_sync_strt_wid ;
2009-08-13 10:32:14 +04:00
bool is_tv = false ;
2009-06-05 16:42:42 +04:00
DRM_DEBUG ( " \n " ) ;
2009-08-13 10:32:14 +04:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
if ( encoder - > crtc = = crtc ) {
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
if ( radeon_encoder - > active_device & ATOM_DEVICE_TV_SUPPORT ) {
is_tv = true ;
DRM_INFO ( " crtc %d is connected to a TV \n " , radeon_crtc - > crtc_id ) ;
break ;
}
}
}
2009-06-05 16:42:42 +04:00
switch ( crtc - > fb - > bits_per_pixel ) {
2009-09-16 04:15:21 +04:00
case 8 :
format = 2 ;
break ;
2009-06-05 16:42:42 +04:00
case 15 : /* 555 */
format = 3 ;
break ;
case 16 : /* 565 */
format = 4 ;
break ;
case 24 : /* RGB */
format = 5 ;
break ;
case 32 : /* xRGB */
format = 6 ;
break ;
default :
return false ;
}
crtc_h_total_disp = ( ( ( ( mode - > crtc_htotal / 8 ) - 1 ) & 0x3ff )
| ( ( ( ( mode - > crtc_hdisplay / 8 ) - 1 ) & 0x1ff ) < < 16 ) ) ;
hsync_wid = ( mode - > crtc_hsync_end - mode - > crtc_hsync_start ) / 8 ;
if ( ! hsync_wid )
hsync_wid = 1 ;
hsync_start = mode - > crtc_hsync_start - 8 ;
crtc_h_sync_strt_wid = ( ( hsync_start & 0x1fff )
| ( ( hsync_wid & 0x3f ) < < 16 )
| ( ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
? RADEON_CRTC_H_SYNC_POL
: 0 ) ) ;
/* This works for double scan mode. */
crtc_v_total_disp = ( ( ( mode - > crtc_vtotal - 1 ) & 0xffff )
| ( ( mode - > crtc_vdisplay - 1 ) < < 16 ) ) ;
vsync_wid = mode - > crtc_vsync_end - mode - > crtc_vsync_start ;
if ( ! vsync_wid )
vsync_wid = 1 ;
crtc_v_sync_strt_wid = ( ( ( mode - > crtc_vsync_start - 1 ) & 0xfff )
| ( ( vsync_wid & 0x1f ) < < 16 )
| ( ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
? RADEON_CRTC_V_SYNC_POL
: 0 ) ) ;
if ( radeon_crtc - > crtc_id ) {
uint32_t crtc2_gen_cntl ;
uint32_t disp2_merge_cntl ;
2009-11-26 17:58:36 +03:00
/* if TV DAC is enabled for another crtc and keep it enabled */
crtc2_gen_cntl = RREG32 ( RADEON_CRTC2_GEN_CNTL ) & 0x00718080 ;
2009-06-05 16:42:42 +04:00
crtc2_gen_cntl | = ( ( format < < 8 )
| RADEON_CRTC2_VSYNC_DIS
| RADEON_CRTC2_HSYNC_DIS
| RADEON_CRTC2_DISP_DIS
| RADEON_CRTC2_DISP_REQ_EN_B
| ( ( mode - > flags & DRM_MODE_FLAG_DBLSCAN )
? RADEON_CRTC2_DBL_SCAN_EN
: 0 )
| ( ( mode - > flags & DRM_MODE_FLAG_CSYNC )
? RADEON_CRTC2_CSYNC_EN
: 0 )
| ( ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
? RADEON_CRTC2_INTERLACE_EN
: 0 ) ) ;
disp2_merge_cntl = RREG32 ( RADEON_DISP2_MERGE_CNTL ) ;
disp2_merge_cntl & = ~ RADEON_DISP2_RGB_OFFSET_EN ;
WREG32 ( RADEON_DISP2_MERGE_CNTL , disp2_merge_cntl ) ;
WREG32 ( RADEON_CRTC2_GEN_CNTL , crtc2_gen_cntl ) ;
2009-10-15 09:33:35 +04:00
WREG32 ( RADEON_FP_H2_SYNC_STRT_WID , crtc_h_sync_strt_wid ) ;
WREG32 ( RADEON_FP_V2_SYNC_STRT_WID , crtc_v_sync_strt_wid ) ;
2009-06-05 16:42:42 +04:00
} else {
uint32_t crtc_gen_cntl ;
uint32_t crtc_ext_cntl ;
uint32_t disp_merge_cntl ;
2009-11-26 17:58:36 +03:00
crtc_gen_cntl = RREG32 ( RADEON_CRTC_GEN_CNTL ) & 0x00718000 ;
crtc_gen_cntl | = ( RADEON_CRTC_EXT_DISP_EN
2009-06-05 16:42:42 +04:00
| ( format < < 8 )
| RADEON_CRTC_DISP_REQ_EN_B
| ( ( mode - > flags & DRM_MODE_FLAG_DBLSCAN )
? RADEON_CRTC_DBL_SCAN_EN
: 0 )
| ( ( mode - > flags & DRM_MODE_FLAG_CSYNC )
? RADEON_CRTC_CSYNC_EN
: 0 )
| ( ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
? RADEON_CRTC_INTERLACE_EN
: 0 ) ) ;
crtc_ext_cntl = RREG32 ( RADEON_CRTC_EXT_CNTL ) ;
crtc_ext_cntl | = ( RADEON_XCRT_CNT_EN |
RADEON_CRTC_VSYNC_DIS |
RADEON_CRTC_HSYNC_DIS |
RADEON_CRTC_DISPLAY_DIS ) ;
disp_merge_cntl = RREG32 ( RADEON_DISP_MERGE_CNTL ) ;
disp_merge_cntl & = ~ RADEON_DISP_RGB_OFFSET_EN ;
WREG32 ( RADEON_DISP_MERGE_CNTL , disp_merge_cntl ) ;
WREG32 ( RADEON_CRTC_GEN_CNTL , crtc_gen_cntl ) ;
WREG32 ( RADEON_CRTC_EXT_CNTL , crtc_ext_cntl ) ;
}
2009-08-13 10:32:14 +04:00
if ( is_tv )
radeon_legacy_tv_adjust_crtc_reg ( encoder , & crtc_h_total_disp ,
& crtc_h_sync_strt_wid , & crtc_v_total_disp ,
& crtc_v_sync_strt_wid ) ;
2009-06-05 16:42:42 +04:00
WREG32 ( RADEON_CRTC_H_TOTAL_DISP + radeon_crtc - > crtc_offset , crtc_h_total_disp ) ;
WREG32 ( RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc - > crtc_offset , crtc_h_sync_strt_wid ) ;
WREG32 ( RADEON_CRTC_V_TOTAL_DISP + radeon_crtc - > crtc_offset , crtc_v_total_disp ) ;
WREG32 ( RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc - > crtc_offset , crtc_v_sync_strt_wid ) ;
return true ;
}
static void radeon_set_pll ( struct drm_crtc * crtc , struct drm_display_mode * mode )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_encoder * encoder ;
uint32_t feedback_div = 0 ;
uint32_t frac_fb_div = 0 ;
uint32_t reference_div = 0 ;
uint32_t post_divider = 0 ;
uint32_t freq = 0 ;
uint8_t pll_gain ;
bool use_bios_divs = false ;
/* PLL registers */
uint32_t pll_ref_div = 0 ;
uint32_t pll_fb_post_div = 0 ;
uint32_t htotal_cntl = 0 ;
2009-08-13 10:32:14 +04:00
bool is_tv = false ;
2009-06-05 16:42:42 +04:00
struct radeon_pll * pll ;
struct {
int divider ;
int bitvalue ;
} * post_div , post_divs [ ] = {
/* From RAGE 128 VR/RAGE 128 GL Register
* Reference Manual ( Technical Reference
* Manual P / N RRG - G04100 - C Rev . 0.04 ) , page
* 3 - 17 ( PLL_DIV_ [ 3 : 0 ] ) .
*/
{ 1 , 0 } , /* VCLK_SRC */
{ 2 , 1 } , /* VCLK_SRC/2 */
{ 4 , 2 } , /* VCLK_SRC/4 */
{ 8 , 3 } , /* VCLK_SRC/8 */
{ 3 , 4 } , /* VCLK_SRC/3 */
{ 16 , 5 } , /* VCLK_SRC/16 */
{ 6 , 6 } , /* VCLK_SRC/6 */
{ 12 , 7 } , /* VCLK_SRC/12 */
{ 0 , 0 }
} ;
if ( radeon_crtc - > crtc_id )
pll = & rdev - > clock . p2pll ;
else
pll = & rdev - > clock . p1pll ;
2010-01-20 01:16:10 +03:00
pll - > flags = RADEON_PLL_LEGACY ;
2010-02-02 20:05:01 +03:00
pll - > algo = PLL_ALGO_LEGACY ;
2010-01-20 01:16:10 +03:00
2009-06-05 16:42:42 +04:00
if ( mode - > clock > 200000 ) /* range limits??? */
2010-01-20 01:16:10 +03:00
pll - > flags | = RADEON_PLL_PREFER_HIGH_FB_DIV ;
2009-06-05 16:42:42 +04:00
else
2010-01-20 01:16:10 +03:00
pll - > flags | = RADEON_PLL_PREFER_LOW_REF_DIV ;
2009-06-05 16:42:42 +04:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
if ( encoder - > crtc = = crtc ) {
2009-08-13 10:32:14 +04:00
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
if ( radeon_encoder - > active_device & ATOM_DEVICE_TV_SUPPORT ) {
is_tv = true ;
break ;
}
2009-06-05 16:42:42 +04:00
if ( encoder - > encoder_type ! = DRM_MODE_ENCODER_DAC )
2010-01-20 01:16:10 +03:00
pll - > flags | = RADEON_PLL_NO_ODD_POST_DIV ;
2009-06-05 16:42:42 +04:00
if ( encoder - > encoder_type = = DRM_MODE_ENCODER_LVDS ) {
2009-12-02 08:59:37 +03:00
if ( ! rdev - > is_atom_bios ) {
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
struct radeon_encoder_lvds * lvds = ( struct radeon_encoder_lvds * ) radeon_encoder - > enc_priv ;
if ( lvds ) {
if ( lvds - > use_bios_dividers ) {
pll_ref_div = lvds - > panel_ref_divider ;
pll_fb_post_div = ( lvds - > panel_fb_divider |
( lvds - > panel_post_divider < < 16 ) ) ;
htotal_cntl = 0 ;
use_bios_divs = true ;
}
2009-06-05 16:42:42 +04:00
}
}
2010-01-20 01:16:10 +03:00
pll - > flags | = RADEON_PLL_USE_REF_DIV ;
2009-06-05 16:42:42 +04:00
}
}
}
DRM_DEBUG ( " \n " ) ;
if ( ! use_bios_divs ) {
radeon_compute_pll ( pll , mode - > clock ,
& freq , & feedback_div , & frac_fb_div ,
2010-01-20 01:16:10 +03:00
& reference_div , & post_divider ) ;
2009-06-05 16:42:42 +04:00
for ( post_div = & post_divs [ 0 ] ; post_div - > divider ; + + post_div ) {
if ( post_div - > divider = = post_divider )
break ;
}
if ( ! post_div - > divider )
post_div = & post_divs [ 0 ] ;
DRM_DEBUG ( " dc=%u, fd=%d, rd=%d, pd=%d \n " ,
( unsigned ) freq ,
feedback_div ,
reference_div ,
post_divider ) ;
pll_ref_div = reference_div ;
# if defined(__powerpc__) && (0) /* TODO */
/* apparently programming this otherwise causes a hang??? */
if ( info - > MacModel = = RADEON_MAC_IBOOK )
pll_fb_post_div = 0x000600ad ;
else
# endif
pll_fb_post_div = ( feedback_div | ( post_div - > bitvalue < < 16 ) ) ;
htotal_cntl = mode - > htotal & 0x7 ;
}
pll_gain = radeon_compute_pll_gain ( pll - > reference_freq ,
pll_ref_div & 0x3ff ,
pll_fb_post_div & 0x7ff ) ;
if ( radeon_crtc - > crtc_id ) {
uint32_t pixclks_cntl = ( ( RREG32_PLL ( RADEON_PIXCLKS_CNTL ) &
~ ( RADEON_PIX2CLK_SRC_SEL_MASK ) ) |
RADEON_PIX2CLK_SRC_SEL_P2PLLCLK ) ;
2009-08-13 10:32:14 +04:00
if ( is_tv ) {
radeon_legacy_tv_adjust_pll2 ( encoder , & htotal_cntl ,
& pll_ref_div , & pll_fb_post_div ,
& pixclks_cntl ) ;
}
2009-06-05 16:42:42 +04:00
WREG32_PLL_P ( RADEON_PIXCLKS_CNTL ,
RADEON_PIX2CLK_SRC_SEL_CPUCLK ,
~ ( RADEON_PIX2CLK_SRC_SEL_MASK ) ) ;
WREG32_PLL_P ( RADEON_P2PLL_CNTL ,
RADEON_P2PLL_RESET
| RADEON_P2PLL_ATOMIC_UPDATE_EN
| ( ( uint32_t ) pll_gain < < RADEON_P2PLL_PVG_SHIFT ) ,
~ ( RADEON_P2PLL_RESET
| RADEON_P2PLL_ATOMIC_UPDATE_EN
| RADEON_P2PLL_PVG_MASK ) ) ;
WREG32_PLL_P ( RADEON_P2PLL_REF_DIV ,
pll_ref_div ,
~ RADEON_P2PLL_REF_DIV_MASK ) ;
WREG32_PLL_P ( RADEON_P2PLL_DIV_0 ,
pll_fb_post_div ,
~ RADEON_P2PLL_FB0_DIV_MASK ) ;
WREG32_PLL_P ( RADEON_P2PLL_DIV_0 ,
pll_fb_post_div ,
~ RADEON_P2PLL_POST0_DIV_MASK ) ;
radeon_pll2_write_update ( dev ) ;
radeon_pll2_wait_for_read_update_complete ( dev ) ;
WREG32_PLL ( RADEON_HTOTAL2_CNTL , htotal_cntl ) ;
WREG32_PLL_P ( RADEON_P2PLL_CNTL ,
0 ,
~ ( RADEON_P2PLL_RESET
| RADEON_P2PLL_SLEEP
| RADEON_P2PLL_ATOMIC_UPDATE_EN ) ) ;
DRM_DEBUG ( " Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x) \n " ,
( unsigned ) pll_ref_div ,
( unsigned ) pll_fb_post_div ,
( unsigned ) htotal_cntl ,
RREG32_PLL ( RADEON_P2PLL_CNTL ) ) ;
DRM_DEBUG ( " Wrote2: rd=%u, fd=%u, pd=%u \n " ,
( unsigned ) pll_ref_div & RADEON_P2PLL_REF_DIV_MASK ,
( unsigned ) pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK ,
( unsigned ) ( ( pll_fb_post_div &
RADEON_P2PLL_POST0_DIV_MASK ) > > 16 ) ) ;
mdelay ( 50 ) ; /* Let the clock to lock */
WREG32_PLL_P ( RADEON_PIXCLKS_CNTL ,
RADEON_PIX2CLK_SRC_SEL_P2PLLCLK ,
~ ( RADEON_PIX2CLK_SRC_SEL_MASK ) ) ;
WREG32_PLL ( RADEON_PIXCLKS_CNTL , pixclks_cntl ) ;
} else {
2009-08-13 10:32:14 +04:00
uint32_t pixclks_cntl ;
if ( is_tv ) {
pixclks_cntl = RREG32_PLL ( RADEON_PIXCLKS_CNTL ) ;
radeon_legacy_tv_adjust_pll1 ( encoder , & htotal_cntl , & pll_ref_div ,
& pll_fb_post_div , & pixclks_cntl ) ;
}
2009-06-05 16:42:42 +04:00
if ( rdev - > flags & RADEON_IS_MOBILITY ) {
/* A temporal workaround for the occational blanking on certain laptop panels.
This appears to related to the PLL divider registers ( fail to lock ? ) .
It occurs even when all dividers are the same with their old settings .
In this case we really don ' t need to fiddle with PLL registers .
By doing this we can avoid the blanking problem with some panels .
*/
if ( ( pll_ref_div = = ( RREG32_PLL ( RADEON_PPLL_REF_DIV ) & RADEON_PPLL_REF_DIV_MASK ) ) & &
( pll_fb_post_div = = ( RREG32_PLL ( RADEON_PPLL_DIV_3 ) &
( RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK ) ) ) ) {
WREG32_P ( RADEON_CLOCK_CNTL_INDEX ,
RADEON_PLL_DIV_SEL ,
~ ( RADEON_PLL_DIV_SEL ) ) ;
r100_pll_errata_after_index ( rdev ) ;
return ;
}
}
WREG32_PLL_P ( RADEON_VCLK_ECP_CNTL ,
RADEON_VCLK_SRC_SEL_CPUCLK ,
~ ( RADEON_VCLK_SRC_SEL_MASK ) ) ;
WREG32_PLL_P ( RADEON_PPLL_CNTL ,
RADEON_PPLL_RESET
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
| ( ( uint32_t ) pll_gain < < RADEON_PPLL_PVG_SHIFT ) ,
~ ( RADEON_PPLL_RESET
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
| RADEON_PPLL_PVG_MASK ) ) ;
WREG32_P ( RADEON_CLOCK_CNTL_INDEX ,
RADEON_PLL_DIV_SEL ,
~ ( RADEON_PLL_DIV_SEL ) ) ;
r100_pll_errata_after_index ( rdev ) ;
if ( ASIC_IS_R300 ( rdev ) | |
( rdev - > family = = CHIP_RS300 ) | |
( rdev - > family = = CHIP_RS400 ) | |
( rdev - > family = = CHIP_RS480 ) ) {
if ( pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK ) {
/* When restoring console mode, use saved PPLL_REF_DIV
* setting .
*/
WREG32_PLL_P ( RADEON_PPLL_REF_DIV ,
pll_ref_div ,
0 ) ;
} else {
/* R300 uses ref_div_acc field as real ref divider */
WREG32_PLL_P ( RADEON_PPLL_REF_DIV ,
( pll_ref_div < < R300_PPLL_REF_DIV_ACC_SHIFT ) ,
~ R300_PPLL_REF_DIV_ACC_MASK ) ;
}
} else
WREG32_PLL_P ( RADEON_PPLL_REF_DIV ,
pll_ref_div ,
~ RADEON_PPLL_REF_DIV_MASK ) ;
WREG32_PLL_P ( RADEON_PPLL_DIV_3 ,
pll_fb_post_div ,
~ RADEON_PPLL_FB3_DIV_MASK ) ;
WREG32_PLL_P ( RADEON_PPLL_DIV_3 ,
pll_fb_post_div ,
~ RADEON_PPLL_POST3_DIV_MASK ) ;
radeon_pll_write_update ( dev ) ;
radeon_pll_wait_for_read_update_complete ( dev ) ;
WREG32_PLL ( RADEON_HTOTAL_CNTL , htotal_cntl ) ;
WREG32_PLL_P ( RADEON_PPLL_CNTL ,
0 ,
~ ( RADEON_PPLL_RESET
| RADEON_PPLL_SLEEP
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN ) ) ;
DRM_DEBUG ( " Wrote: 0x%08x 0x%08x 0x%08x (0x%08x) \n " ,
pll_ref_div ,
pll_fb_post_div ,
( unsigned ) htotal_cntl ,
RREG32_PLL ( RADEON_PPLL_CNTL ) ) ;
DRM_DEBUG ( " Wrote: rd=%d, fd=%d, pd=%d \n " ,
pll_ref_div & RADEON_PPLL_REF_DIV_MASK ,
pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK ,
( pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK ) > > 16 ) ;
mdelay ( 50 ) ; /* Let the clock to lock */
WREG32_PLL_P ( RADEON_VCLK_ECP_CNTL ,
RADEON_VCLK_SRC_SEL_PPLLCLK ,
~ ( RADEON_VCLK_SRC_SEL_MASK ) ) ;
2009-08-13 10:32:14 +04:00
if ( is_tv )
WREG32_PLL ( RADEON_PIXCLKS_CNTL , pixclks_cntl ) ;
2009-06-05 16:42:42 +04:00
}
}
static bool radeon_crtc_mode_fixup ( struct drm_crtc * crtc ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
2009-07-13 23:04:08 +04:00
if ( ! radeon_crtc_scaling_mode_fixup ( crtc , mode , adjusted_mode ) )
return false ;
2009-06-05 16:42:42 +04:00
return true ;
}
static int radeon_crtc_mode_set ( struct drm_crtc * crtc ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode ,
int x , int y , struct drm_framebuffer * old_fb )
{
2009-07-13 23:04:08 +04:00
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
2009-06-05 16:42:42 +04:00
/* TODO TV */
radeon_crtc_set_base ( crtc , x , y , old_fb ) ;
radeon_set_crtc_timing ( crtc , adjusted_mode ) ;
radeon_set_pll ( crtc , adjusted_mode ) ;
2009-12-04 18:40:41 +03:00
radeon_overscan_setup ( crtc , adjusted_mode ) ;
2009-07-13 23:04:08 +04:00
if ( radeon_crtc - > crtc_id = = 0 ) {
2009-12-17 09:24:59 +03:00
radeon_legacy_rmx_mode_set ( crtc , adjusted_mode ) ;
2009-07-13 23:04:08 +04:00
} else {
if ( radeon_crtc - > rmx_type ! = RMX_OFF ) {
/* FIXME: only first crtc has rmx what should we
* do ?
*/
DRM_ERROR ( " Mode need scaling but only first crtc can do that. \n " ) ;
}
}
2009-06-05 16:42:42 +04:00
return 0 ;
}
static void radeon_crtc_prepare ( struct drm_crtc * crtc )
{
2009-11-30 23:15:44 +03:00
struct drm_device * dev = crtc - > dev ;
struct drm_crtc * crtci ;
/*
* The hardware wedges sometimes if you reconfigure one CRTC
* whilst another is running ( see fdo bug # 24611 ) .
*/
list_for_each_entry ( crtci , & dev - > mode_config . crtc_list , head )
radeon_crtc_dpms ( crtci , DRM_MODE_DPMS_OFF ) ;
2009-06-05 16:42:42 +04:00
}
static void radeon_crtc_commit ( struct drm_crtc * crtc )
{
2009-11-30 23:15:44 +03:00
struct drm_device * dev = crtc - > dev ;
struct drm_crtc * crtci ;
/*
* Reenable the CRTCs that should be running .
*/
list_for_each_entry ( crtci , & dev - > mode_config . crtc_list , head ) {
if ( crtci - > enabled )
radeon_crtc_dpms ( crtci , DRM_MODE_DPMS_ON ) ;
}
2009-06-05 16:42:42 +04:00
}
static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
. dpms = radeon_crtc_dpms ,
. mode_fixup = radeon_crtc_mode_fixup ,
. mode_set = radeon_crtc_mode_set ,
. mode_set_base = radeon_crtc_set_base ,
. prepare = radeon_crtc_prepare ,
. commit = radeon_crtc_commit ,
2009-10-05 03:58:02 +04:00
. load_lut = radeon_crtc_load_lut ,
2009-06-05 16:42:42 +04:00
} ;
void radeon_legacy_init_crtc ( struct drm_device * dev ,
struct radeon_crtc * radeon_crtc )
{
if ( radeon_crtc - > crtc_id = = 1 )
radeon_crtc - > crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP ;
drm_crtc_helper_add ( & radeon_crtc - > base , & legacy_helper_funcs ) ;
}