2009-06-05 14:42:42 +02: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>
2010-04-28 11:46:42 +10:00
# include <drm/drm_fixed.h>
2009-06-05 14:42:42 +02:00
# include "radeon.h"
# include "atom.h"
# include "atom-bits.h"
2009-07-13 21:04:08 +02:00
static void atombios_overscan_setup ( struct drm_crtc * crtc ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
SET_CRTC_OVERSCAN_PS_ALLOCATION args ;
int index = GetIndexIntoMasterTable ( COMMAND , SetCRTC_OverScan ) ;
int a1 , a2 ;
memset ( & args , 0 , sizeof ( args ) ) ;
args . usOverscanRight = 0 ;
args . usOverscanLeft = 0 ;
args . usOverscanBottom = 0 ;
args . usOverscanTop = 0 ;
args . ucCRTC = radeon_crtc - > crtc_id ;
switch ( radeon_crtc - > rmx_type ) {
case RMX_CENTER :
args . usOverscanTop = ( adjusted_mode - > crtc_vdisplay - mode - > crtc_vdisplay ) / 2 ;
args . usOverscanBottom = ( adjusted_mode - > crtc_vdisplay - mode - > crtc_vdisplay ) / 2 ;
args . usOverscanLeft = ( adjusted_mode - > crtc_hdisplay - mode - > crtc_hdisplay ) / 2 ;
args . usOverscanRight = ( adjusted_mode - > crtc_hdisplay - mode - > crtc_hdisplay ) / 2 ;
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
break ;
case RMX_ASPECT :
a1 = mode - > crtc_vdisplay * adjusted_mode - > crtc_hdisplay ;
a2 = adjusted_mode - > crtc_vdisplay * mode - > crtc_hdisplay ;
if ( a1 > a2 ) {
args . usOverscanLeft = ( adjusted_mode - > crtc_hdisplay - ( a2 / mode - > crtc_vdisplay ) ) / 2 ;
args . usOverscanRight = ( adjusted_mode - > crtc_hdisplay - ( a2 / mode - > crtc_vdisplay ) ) / 2 ;
} else if ( a2 > a1 ) {
args . usOverscanLeft = ( adjusted_mode - > crtc_vdisplay - ( a1 / mode - > crtc_hdisplay ) ) / 2 ;
args . usOverscanRight = ( adjusted_mode - > crtc_vdisplay - ( a1 / mode - > crtc_hdisplay ) ) / 2 ;
}
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
break ;
case RMX_FULL :
default :
args . usOverscanRight = 0 ;
args . usOverscanLeft = 0 ;
args . usOverscanBottom = 0 ;
args . usOverscanTop = 0 ;
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
break ;
}
}
static void atombios_scaler_setup ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
ENABLE_SCALER_PS_ALLOCATION args ;
int index = GetIndexIntoMasterTable ( COMMAND , EnableScaler ) ;
2009-08-13 16:32:14 +10:00
2009-07-13 21:04:08 +02:00
/* fixme - fill in enc_priv for atom dac */
enum radeon_tv_std tv_std = TV_STD_NTSC ;
2009-08-13 16:32:14 +10:00
bool is_tv = false , is_cv = false ;
struct drm_encoder * encoder ;
2009-07-13 21:04:08 +02:00
if ( ! ASIC_IS_AVIVO ( rdev ) & & radeon_crtc - > crtc_id )
return ;
2009-08-13 16:32:14 +10:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
/* find tv std */
if ( encoder - > crtc = = crtc ) {
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
if ( radeon_encoder - > active_device & ATOM_DEVICE_TV_SUPPORT ) {
struct radeon_encoder_atom_dac * tv_dac = radeon_encoder - > enc_priv ;
tv_std = tv_dac - > tv_std ;
is_tv = true ;
}
}
}
2009-07-13 21:04:08 +02:00
memset ( & args , 0 , sizeof ( args ) ) ;
args . ucScaler = radeon_crtc - > crtc_id ;
2009-08-13 16:32:14 +10:00
if ( is_tv ) {
2009-07-13 21:04:08 +02:00
switch ( tv_std ) {
case TV_STD_NTSC :
default :
args . ucTVStandard = ATOM_TV_NTSC ;
break ;
case TV_STD_PAL :
args . ucTVStandard = ATOM_TV_PAL ;
break ;
case TV_STD_PAL_M :
args . ucTVStandard = ATOM_TV_PALM ;
break ;
case TV_STD_PAL_60 :
args . ucTVStandard = ATOM_TV_PAL60 ;
break ;
case TV_STD_NTSC_J :
args . ucTVStandard = ATOM_TV_NTSCJ ;
break ;
case TV_STD_SCART_PAL :
args . ucTVStandard = ATOM_TV_PAL ; /* ??? */
break ;
case TV_STD_SECAM :
args . ucTVStandard = ATOM_TV_SECAM ;
break ;
case TV_STD_PAL_CN :
args . ucTVStandard = ATOM_TV_PALCN ;
break ;
}
args . ucEnable = SCALER_ENABLE_MULTITAP_MODE ;
2009-08-13 16:32:14 +10:00
} else if ( is_cv ) {
2009-07-13 21:04:08 +02:00
args . ucTVStandard = ATOM_TV_CV ;
args . ucEnable = SCALER_ENABLE_MULTITAP_MODE ;
} else {
switch ( radeon_crtc - > rmx_type ) {
case RMX_FULL :
args . ucEnable = ATOM_SCALER_EXPANSION ;
break ;
case RMX_CENTER :
args . ucEnable = ATOM_SCALER_CENTER ;
break ;
case RMX_ASPECT :
args . ucEnable = ATOM_SCALER_EXPANSION ;
break ;
default :
if ( ASIC_IS_AVIVO ( rdev ) )
args . ucEnable = ATOM_SCALER_DISABLE ;
else
args . ucEnable = ATOM_SCALER_CENTER ;
break ;
}
}
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
2009-08-13 16:32:14 +10:00
if ( ( is_tv | | is_cv )
& & rdev - > family > = CHIP_RV515 & & rdev - > family < = CHIP_R580 ) {
atom_rv515_force_tv_scaler ( rdev , radeon_crtc ) ;
2009-07-13 21:04:08 +02:00
}
}
2009-06-05 14:42:42 +02:00
static void atombios_lock_crtc ( struct drm_crtc * crtc , int lock )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
int index =
GetIndexIntoMasterTable ( COMMAND , UpdateCRTC_DoubleBufferRegisters ) ;
ENABLE_CRTC_PS_ALLOCATION args ;
memset ( & args , 0 , sizeof ( args ) ) ;
args . ucCRTC = radeon_crtc - > crtc_id ;
args . ucEnable = lock ;
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
}
static void atombios_enable_crtc ( struct drm_crtc * crtc , int state )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
int index = GetIndexIntoMasterTable ( COMMAND , EnableCRTC ) ;
ENABLE_CRTC_PS_ALLOCATION args ;
memset ( & args , 0 , sizeof ( args ) ) ;
args . ucCRTC = radeon_crtc - > crtc_id ;
args . ucEnable = state ;
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
}
static void atombios_enable_crtc_memreq ( struct drm_crtc * crtc , int state )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
int index = GetIndexIntoMasterTable ( COMMAND , EnableCRTCMemReq ) ;
ENABLE_CRTC_PS_ALLOCATION args ;
memset ( & args , 0 , sizeof ( args ) ) ;
args . ucCRTC = radeon_crtc - > crtc_id ;
args . ucEnable = state ;
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
}
static void atombios_blank_crtc ( struct drm_crtc * crtc , int state )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
int index = GetIndexIntoMasterTable ( COMMAND , BlankCRTC ) ;
BLANK_CRTC_PS_ALLOCATION args ;
memset ( & args , 0 , sizeof ( args ) ) ;
args . ucCRTC = radeon_crtc - > crtc_id ;
args . ucBlanking = state ;
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
}
void atombios_crtc_dpms ( struct drm_crtc * crtc , int mode )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
2009-12-02 11:46:52 -05:00
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
2009-06-05 14:42:42 +02:00
switch ( mode ) {
case DRM_MODE_DPMS_ON :
2010-05-03 01:13:14 -04:00
radeon_crtc - > enabled = true ;
/* adjust pm to dpms changes BEFORE enabling crtcs */
radeon_pm_compute_clocks ( rdev ) ;
2010-02-09 12:04:43 -05:00
atombios_enable_crtc ( crtc , ATOM_ENABLE ) ;
2009-06-05 14:42:42 +02:00
if ( ASIC_IS_DCE3 ( rdev ) )
2010-02-09 12:04:43 -05:00
atombios_enable_crtc_memreq ( crtc , ATOM_ENABLE ) ;
atombios_blank_crtc ( crtc , ATOM_DISABLE ) ;
2010-03-24 13:55:51 -04:00
drm_vblank_post_modeset ( dev , radeon_crtc - > crtc_id ) ;
2009-12-02 11:46:52 -05:00
radeon_crtc_load_lut ( crtc ) ;
2009-06-05 14:42:42 +02:00
break ;
case DRM_MODE_DPMS_STANDBY :
case DRM_MODE_DPMS_SUSPEND :
case DRM_MODE_DPMS_OFF :
2010-03-24 13:55:51 -04:00
drm_vblank_pre_modeset ( dev , radeon_crtc - > crtc_id ) ;
2010-02-09 12:04:43 -05:00
atombios_blank_crtc ( crtc , ATOM_ENABLE ) ;
2009-06-05 14:42:42 +02:00
if ( ASIC_IS_DCE3 ( rdev ) )
2010-02-09 12:04:43 -05:00
atombios_enable_crtc_memreq ( crtc , ATOM_DISABLE ) ;
atombios_enable_crtc ( crtc , ATOM_DISABLE ) ;
2010-04-22 14:03:55 -04:00
radeon_crtc - > enabled = false ;
2010-05-03 01:13:14 -04:00
/* adjust pm to dpms changes AFTER disabling crtcs */
radeon_pm_compute_clocks ( rdev ) ;
2009-06-05 14:42:42 +02:00
break ;
}
}
static void
atombios_set_crtc_dtd_timing ( struct drm_crtc * crtc ,
2009-10-08 15:09:31 -04:00
struct drm_display_mode * mode )
2009-06-05 14:42:42 +02:00
{
2009-10-08 15:09:31 -04:00
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
2009-06-05 14:42:42 +02:00
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
2009-10-08 15:09:31 -04:00
SET_CRTC_USING_DTD_TIMING_PARAMETERS args ;
2009-06-05 14:42:42 +02:00
int index = GetIndexIntoMasterTable ( COMMAND , SetCRTC_UsingDTDTiming ) ;
2009-10-08 15:09:31 -04:00
u16 misc = 0 ;
2009-06-05 14:42:42 +02:00
2009-10-08 15:09:31 -04:00
memset ( & args , 0 , sizeof ( args ) ) ;
args . usH_Size = cpu_to_le16 ( mode - > crtc_hdisplay ) ;
args . usH_Blanking_Time =
cpu_to_le16 ( mode - > crtc_hblank_end - mode - > crtc_hdisplay ) ;
args . usV_Size = cpu_to_le16 ( mode - > crtc_vdisplay ) ;
args . usV_Blanking_Time =
cpu_to_le16 ( mode - > crtc_vblank_end - mode - > crtc_vdisplay ) ;
args . usH_SyncOffset =
cpu_to_le16 ( mode - > crtc_hsync_start - mode - > crtc_hdisplay ) ;
args . usH_SyncWidth =
cpu_to_le16 ( mode - > crtc_hsync_end - mode - > crtc_hsync_start ) ;
args . usV_SyncOffset =
cpu_to_le16 ( mode - > crtc_vsync_start - mode - > crtc_vdisplay ) ;
args . usV_SyncWidth =
cpu_to_le16 ( mode - > crtc_vsync_end - mode - > crtc_vsync_start ) ;
/*args.ucH_Border = mode->hborder;*/
/*args.ucV_Border = mode->vborder;*/
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
misc | = ATOM_VSYNC_POLARITY ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
misc | = ATOM_HSYNC_POLARITY ;
if ( mode - > flags & DRM_MODE_FLAG_CSYNC )
misc | = ATOM_COMPOSITESYNC ;
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
misc | = ATOM_INTERLACE ;
if ( mode - > flags & DRM_MODE_FLAG_DBLSCAN )
misc | = ATOM_DOUBLE_CLOCK_MODE ;
args . susModeMiscInfo . usAccess = cpu_to_le16 ( misc ) ;
args . ucCRTC = radeon_crtc - > crtc_id ;
2009-06-05 14:42:42 +02:00
2009-10-08 15:09:31 -04:00
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
2009-06-05 14:42:42 +02:00
}
2009-10-08 15:09:31 -04:00
static void atombios_crtc_set_timing ( struct drm_crtc * crtc ,
struct drm_display_mode * mode )
2009-06-05 14:42:42 +02:00
{
2009-10-08 15:09:31 -04:00
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
2009-06-05 14:42:42 +02:00
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
2009-10-08 15:09:31 -04:00
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args ;
2009-06-05 14:42:42 +02:00
int index = GetIndexIntoMasterTable ( COMMAND , SetCRTC_Timing ) ;
2009-10-08 15:09:31 -04:00
u16 misc = 0 ;
2009-06-05 14:42:42 +02:00
2009-10-08 15:09:31 -04:00
memset ( & args , 0 , sizeof ( args ) ) ;
args . usH_Total = cpu_to_le16 ( mode - > crtc_htotal ) ;
args . usH_Disp = cpu_to_le16 ( mode - > crtc_hdisplay ) ;
args . usH_SyncStart = cpu_to_le16 ( mode - > crtc_hsync_start ) ;
args . usH_SyncWidth =
cpu_to_le16 ( mode - > crtc_hsync_end - mode - > crtc_hsync_start ) ;
args . usV_Total = cpu_to_le16 ( mode - > crtc_vtotal ) ;
args . usV_Disp = cpu_to_le16 ( mode - > crtc_vdisplay ) ;
args . usV_SyncStart = cpu_to_le16 ( mode - > crtc_vsync_start ) ;
args . usV_SyncWidth =
cpu_to_le16 ( mode - > crtc_vsync_end - mode - > crtc_vsync_start ) ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
misc | = ATOM_VSYNC_POLARITY ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
misc | = ATOM_HSYNC_POLARITY ;
if ( mode - > flags & DRM_MODE_FLAG_CSYNC )
misc | = ATOM_COMPOSITESYNC ;
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
misc | = ATOM_INTERLACE ;
if ( mode - > flags & DRM_MODE_FLAG_DBLSCAN )
misc | = ATOM_DOUBLE_CLOCK_MODE ;
args . susModeMiscInfo . usAccess = cpu_to_le16 ( misc ) ;
args . ucCRTC = radeon_crtc - > crtc_id ;
2009-06-05 14:42:42 +02:00
2009-10-08 15:09:31 -04:00
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
2009-06-05 14:42:42 +02:00
}
2010-03-06 10:57:30 -05:00
static void atombios_disable_ss ( struct drm_crtc * crtc )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
u32 ss_cntl ;
if ( ASIC_IS_DCE4 ( rdev ) ) {
switch ( radeon_crtc - > pll_id ) {
case ATOM_PPLL1 :
ss_cntl = RREG32 ( EVERGREEN_P1PLL_SS_CNTL ) ;
ss_cntl & = ~ EVERGREEN_PxPLL_SS_EN ;
WREG32 ( EVERGREEN_P1PLL_SS_CNTL , ss_cntl ) ;
break ;
case ATOM_PPLL2 :
ss_cntl = RREG32 ( EVERGREEN_P2PLL_SS_CNTL ) ;
ss_cntl & = ~ EVERGREEN_PxPLL_SS_EN ;
WREG32 ( EVERGREEN_P2PLL_SS_CNTL , ss_cntl ) ;
break ;
case ATOM_DCPLL :
case ATOM_PPLL_INVALID :
return ;
}
} else if ( ASIC_IS_AVIVO ( rdev ) ) {
switch ( radeon_crtc - > pll_id ) {
case ATOM_PPLL1 :
ss_cntl = RREG32 ( AVIVO_P1PLL_INT_SS_CNTL ) ;
ss_cntl & = ~ 1 ;
WREG32 ( AVIVO_P1PLL_INT_SS_CNTL , ss_cntl ) ;
break ;
case ATOM_PPLL2 :
ss_cntl = RREG32 ( AVIVO_P2PLL_INT_SS_CNTL ) ;
ss_cntl & = ~ 1 ;
WREG32 ( AVIVO_P2PLL_INT_SS_CNTL , ss_cntl ) ;
break ;
case ATOM_DCPLL :
case ATOM_PPLL_INVALID :
return ;
}
}
}
2010-02-01 16:39:11 -05:00
union atom_enable_ss {
ENABLE_LVDS_SS_PARAMETERS legacy ;
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1 ;
} ;
2010-03-06 10:57:30 -05:00
static void atombios_enable_ss ( struct drm_crtc * crtc )
2009-10-16 11:15:25 -04:00
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct drm_encoder * encoder = NULL ;
struct radeon_encoder * radeon_encoder = NULL ;
struct radeon_encoder_atom_dig * dig = NULL ;
int index = GetIndexIntoMasterTable ( COMMAND , EnableSpreadSpectrumOnPPLL ) ;
2010-02-01 16:39:11 -05:00
union atom_enable_ss args ;
2009-10-16 11:15:25 -04:00
uint16_t percentage = 0 ;
uint8_t type = 0 , step = 0 , delay = 0 , range = 0 ;
2010-01-12 17:54:34 -05:00
/* XXX add ss support for DCE4 */
if ( ASIC_IS_DCE4 ( rdev ) )
return ;
2009-10-16 11:15:25 -04:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
if ( encoder - > crtc = = crtc ) {
radeon_encoder = to_radeon_encoder ( encoder ) ;
/* only enable spread spectrum on LVDS */
2009-10-28 00:51:20 -04:00
if ( radeon_encoder - > devices & ( ATOM_DEVICE_LCD_SUPPORT ) ) {
dig = radeon_encoder - > enc_priv ;
if ( dig & & dig - > ss ) {
percentage = dig - > ss - > percentage ;
type = dig - > ss - > type ;
step = dig - > ss - > step ;
delay = dig - > ss - > delay ;
range = dig - > ss - > range ;
2010-03-06 10:57:30 -05:00
} else
2009-10-28 00:51:20 -04:00
return ;
2010-03-06 10:57:30 -05:00
} else
2009-10-16 11:15:25 -04:00
return ;
break ;
}
}
if ( ! radeon_encoder )
return ;
2010-02-01 16:39:11 -05:00
memset ( & args , 0 , sizeof ( args ) ) ;
2009-10-16 11:15:25 -04:00
if ( ASIC_IS_AVIVO ( rdev ) ) {
2010-02-01 16:39:11 -05:00
args . v1 . usSpreadSpectrumPercentage = cpu_to_le16 ( percentage ) ;
args . v1 . ucSpreadSpectrumType = type ;
args . v1 . ucSpreadSpectrumStep = step ;
args . v1 . ucSpreadSpectrumDelay = delay ;
args . v1 . ucSpreadSpectrumRange = range ;
args . v1 . ucPpll = radeon_crtc - > crtc_id ? ATOM_PPLL2 : ATOM_PPLL1 ;
2010-03-06 10:57:30 -05:00
args . v1 . ucEnable = ATOM_ENABLE ;
2009-10-16 11:15:25 -04:00
} else {
2010-02-01 16:39:11 -05:00
args . legacy . usSpreadSpectrumPercentage = cpu_to_le16 ( percentage ) ;
args . legacy . ucSpreadSpectrumType = type ;
args . legacy . ucSpreadSpectrumStepSize_Delay = ( step & 3 ) < < 2 ;
args . legacy . ucSpreadSpectrumStepSize_Delay | = ( delay & 7 ) < < 4 ;
2010-03-06 10:57:30 -05:00
args . legacy . ucEnable = ATOM_ENABLE ;
2009-10-16 11:15:25 -04:00
}
2010-02-01 16:39:11 -05:00
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
2009-10-16 11:15:25 -04:00
}
2010-01-19 17:32:27 -05:00
union adjust_pixel_clock {
ADJUST_DISPLAY_PLL_PS_ALLOCATION v1 ;
2010-01-12 17:54:34 -05:00
ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3 ;
2010-01-19 17:32:27 -05:00
} ;
static u32 atombios_adjust_pll ( struct drm_crtc * crtc ,
struct drm_display_mode * mode ,
struct radeon_pll * pll )
2009-06-05 14:42:42 +02:00
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct drm_encoder * encoder = NULL ;
struct radeon_encoder * radeon_encoder = NULL ;
2010-01-19 17:32:27 -05:00
u32 adjusted_clock = mode - > clock ;
2010-01-12 17:54:34 -05:00
int encoder_mode = 0 ;
2010-01-19 17:16:10 -05:00
2010-01-19 17:32:27 -05:00
/* reset the pll flags */
pll - > flags = 0 ;
2009-06-05 14:42:42 +02:00
2010-02-02 12:05:01 -05:00
/* select the PLL algo */
if ( ASIC_IS_AVIVO ( rdev ) ) {
2010-02-23 03:24:38 -05:00
if ( radeon_new_pll = = 0 )
pll - > algo = PLL_ALGO_LEGACY ;
else
pll - > algo = PLL_ALGO_NEW ;
} else {
if ( radeon_new_pll = = 1 )
pll - > algo = PLL_ALGO_NEW ;
2010-02-02 12:05:01 -05:00
else
pll - > algo = PLL_ALGO_LEGACY ;
2010-02-23 03:24:38 -05:00
}
2010-02-02 12:05:01 -05:00
2009-06-05 14:42:42 +02:00
if ( ASIC_IS_AVIVO ( rdev ) ) {
2009-07-13 11:09:56 -04:00
if ( ( rdev - > family = = CHIP_RS600 ) | |
( rdev - > family = = CHIP_RS690 ) | |
( rdev - > family = = CHIP_RS740 ) )
2010-01-19 17:16:10 -05:00
pll - > flags | = ( RADEON_PLL_USE_FRAC_FB_DIV |
RADEON_PLL_PREFER_CLOSEST_LOWER ) ;
2009-07-13 11:09:56 -04:00
2009-06-05 14:42:42 +02:00
if ( ASIC_IS_DCE32 ( rdev ) & & mode - > clock > 200000 ) /* range limits??? */
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_PREFER_HIGH_FB_DIV ;
2009-06-05 14:42:42 +02:00
else
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_PREFER_LOW_REF_DIV ;
2009-06-05 14:42:42 +02:00
} else {
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_LEGACY ;
2009-06-05 14:42:42 +02:00
if ( mode - > clock > 200000 ) /* range limits??? */
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_PREFER_HIGH_FB_DIV ;
2009-06-05 14:42:42 +02:00
else
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_PREFER_LOW_REF_DIV ;
2009-06-05 14:42:42 +02:00
}
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
if ( encoder - > crtc = = crtc ) {
2010-01-19 17:32:27 -05:00
radeon_encoder = to_radeon_encoder ( encoder ) ;
2010-01-12 17:54:34 -05:00
encoder_mode = atombios_get_encoder_mode ( encoder ) ;
2010-01-19 17:32:27 -05:00
if ( ASIC_IS_AVIVO ( rdev ) ) {
/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
if ( radeon_encoder - > encoder_id = = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 )
adjusted_clock = mode - > clock * 2 ;
2010-04-09 15:31:56 -04:00
if ( radeon_encoder - > active_device & ( ATOM_DEVICE_TV_SUPPORT ) ) {
pll - > algo = PLL_ALGO_LEGACY ;
pll - > flags | = RADEON_PLL_PREFER_CLOSEST_LOWER ;
}
2010-01-19 17:32:27 -05:00
} else {
if ( encoder - > encoder_type ! = DRM_MODE_ENCODER_DAC )
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_NO_ODD_POST_DIV ;
2010-01-19 17:32:27 -05:00
if ( encoder - > encoder_type = = DRM_MODE_ENCODER_LVDS )
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_USE_REF_DIV ;
2009-06-05 14:42:42 +02:00
}
2009-09-08 10:10:24 +10:00
break ;
2009-06-05 14:42:42 +02:00
}
}
2009-10-08 13:36:21 -04:00
/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
* accordingly based on the encoder / transmitter to work around
* special hw requirements .
*/
if ( ASIC_IS_DCE3 ( rdev ) ) {
2010-01-19 17:32:27 -05:00
union adjust_pixel_clock args ;
u8 frev , crev ;
int index ;
2009-10-08 13:36:21 -04:00
index = GetIndexIntoMasterTable ( COMMAND , AdjustDisplayPll ) ;
2010-03-18 01:04:01 -04:00
if ( ! atom_parse_cmd_header ( rdev - > mode_info . atom_context , index , & frev ,
& crev ) )
return adjusted_clock ;
2010-01-19 17:32:27 -05:00
memset ( & args , 0 , sizeof ( args ) ) ;
switch ( frev ) {
case 1 :
switch ( crev ) {
case 1 :
case 2 :
args . v1 . usPixelClock = cpu_to_le16 ( mode - > clock / 10 ) ;
args . v1 . ucTransmitterID = radeon_encoder - > encoder_id ;
2010-01-12 17:54:34 -05:00
args . v1 . ucEncodeMode = encoder_mode ;
2010-01-19 17:32:27 -05:00
atom_execute_table ( rdev - > mode_info . atom_context ,
index , ( uint32_t * ) & args ) ;
adjusted_clock = le16_to_cpu ( args . v1 . usPixelClock ) * 10 ;
break ;
2010-01-12 17:54:34 -05:00
case 3 :
args . v3 . sInput . usPixelClock = cpu_to_le16 ( mode - > clock / 10 ) ;
args . v3 . sInput . ucTransmitterID = radeon_encoder - > encoder_id ;
args . v3 . sInput . ucEncodeMode = encoder_mode ;
args . v3 . sInput . ucDispPllConfig = 0 ;
if ( radeon_encoder - > devices & ( ATOM_DEVICE_DFP_SUPPORT ) ) {
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
if ( encoder_mode = = ATOM_ENCODER_MODE_DP )
args . v3 . sInput . ucDispPllConfig | =
DISPPLL_CONFIG_COHERENT_MODE ;
else {
if ( dig - > coherent_mode )
args . v3 . sInput . ucDispPllConfig | =
DISPPLL_CONFIG_COHERENT_MODE ;
if ( mode - > clock > 165000 )
args . v3 . sInput . ucDispPllConfig | =
DISPPLL_CONFIG_DUAL_LINK ;
}
} else if ( radeon_encoder - > devices & ( ATOM_DEVICE_LCD_SUPPORT ) ) {
/* may want to enable SS on DP/eDP eventually */
2010-03-29 21:37:08 -04:00
/*args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_SS_ENABLE ; */
if ( encoder_mode = = ATOM_ENCODER_MODE_DP )
2010-01-12 17:54:34 -05:00
args . v3 . sInput . ucDispPllConfig | =
2010-03-29 21:37:08 -04:00
DISPPLL_CONFIG_COHERENT_MODE ;
else {
if ( mode - > clock > 165000 )
args . v3 . sInput . ucDispPllConfig | =
DISPPLL_CONFIG_DUAL_LINK ;
}
2010-01-12 17:54:34 -05:00
}
atom_execute_table ( rdev - > mode_info . atom_context ,
index , ( uint32_t * ) & args ) ;
adjusted_clock = le32_to_cpu ( args . v3 . sOutput . ulDispPllFreq ) * 10 ;
if ( args . v3 . sOutput . ucRefDiv ) {
pll - > flags | = RADEON_PLL_USE_REF_DIV ;
pll - > reference_div = args . v3 . sOutput . ucRefDiv ;
}
if ( args . v3 . sOutput . ucPostDiv ) {
pll - > flags | = RADEON_PLL_USE_POST_DIV ;
pll - > post_div = args . v3 . sOutput . ucPostDiv ;
}
break ;
2010-01-19 17:32:27 -05:00
default :
DRM_ERROR ( " Unknown table version %d %d \n " , frev , crev ) ;
return adjusted_clock ;
}
break ;
default :
DRM_ERROR ( " Unknown table version %d %d \n " , frev , crev ) ;
return adjusted_clock ;
}
2009-10-27 12:11:09 -04:00
}
2010-01-19 17:32:27 -05:00
return adjusted_clock ;
}
union set_pixel_clock {
SET_PIXEL_CLOCK_PS_ALLOCATION base ;
PIXEL_CLOCK_PARAMETERS v1 ;
PIXEL_CLOCK_PARAMETERS_V2 v2 ;
PIXEL_CLOCK_PARAMETERS_V3 v3 ;
2010-01-12 17:54:34 -05:00
PIXEL_CLOCK_PARAMETERS_V5 v5 ;
2010-01-19 17:32:27 -05:00
} ;
2010-01-12 17:54:34 -05:00
static void atombios_crtc_set_dcpll ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
u8 frev , crev ;
int index ;
union set_pixel_clock args ;
memset ( & args , 0 , sizeof ( args ) ) ;
index = GetIndexIntoMasterTable ( COMMAND , SetPixelClock ) ;
2010-03-18 01:04:01 -04:00
if ( ! atom_parse_cmd_header ( rdev - > mode_info . atom_context , index , & frev ,
& crev ) )
return ;
2010-01-12 17:54:34 -05:00
switch ( frev ) {
case 1 :
switch ( crev ) {
case 5 :
/* if the default dcpll clock is specified,
* SetPixelClock provides the dividers
*/
args . v5 . ucCRTC = ATOM_CRTC_INVALID ;
args . v5 . usPixelClock = rdev - > clock . default_dispclk ;
args . v5 . ucPpll = ATOM_DCPLL ;
break ;
default :
DRM_ERROR ( " Unknown table version %d %d \n " , frev , crev ) ;
return ;
}
break ;
default :
DRM_ERROR ( " Unknown table version %d %d \n " , frev , crev ) ;
return ;
}
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
}
static void atombios_crtc_set_pll ( struct drm_crtc * crtc , struct drm_display_mode * mode )
2010-01-19 17:32:27 -05:00
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct drm_encoder * encoder = NULL ;
struct radeon_encoder * radeon_encoder = NULL ;
u8 frev , crev ;
int index ;
union set_pixel_clock args ;
u32 pll_clock = mode - > clock ;
u32 ref_div = 0 , fb_div = 0 , frac_fb_div = 0 , post_div = 0 ;
struct radeon_pll * pll ;
u32 adjusted_clock ;
2010-01-12 17:54:34 -05:00
int encoder_mode = 0 ;
2010-01-19 17:32:27 -05:00
memset ( & args , 0 , sizeof ( args ) ) ;
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
if ( encoder - > crtc = = crtc ) {
radeon_encoder = to_radeon_encoder ( encoder ) ;
2010-01-12 17:54:34 -05:00
encoder_mode = atombios_get_encoder_mode ( encoder ) ;
2010-01-19 17:32:27 -05:00
break ;
}
}
if ( ! radeon_encoder )
return ;
2010-01-12 17:54:34 -05:00
switch ( radeon_crtc - > pll_id ) {
case ATOM_PPLL1 :
2010-01-19 17:32:27 -05:00
pll = & rdev - > clock . p1pll ;
2010-01-12 17:54:34 -05:00
break ;
case ATOM_PPLL2 :
2010-01-19 17:32:27 -05:00
pll = & rdev - > clock . p2pll ;
2010-01-12 17:54:34 -05:00
break ;
case ATOM_DCPLL :
case ATOM_PPLL_INVALID :
2010-05-26 10:27:44 +10:00
default :
2010-01-12 17:54:34 -05:00
pll = & rdev - > clock . dcpll ;
break ;
}
2010-01-19 17:32:27 -05:00
/* adjust pixel clock as needed */
adjusted_clock = atombios_adjust_pll ( crtc , mode , pll ) ;
2009-10-08 13:36:21 -04:00
2010-02-02 12:05:01 -05:00
radeon_compute_pll ( pll , adjusted_clock , & pll_clock , & fb_div , & frac_fb_div ,
& ref_div , & post_div ) ;
2009-06-05 14:42:42 +02:00
2009-10-12 14:21:19 +10:00
index = GetIndexIntoMasterTable ( COMMAND , SetPixelClock ) ;
2010-03-18 01:04:01 -04:00
if ( ! atom_parse_cmd_header ( rdev - > mode_info . atom_context , index , & frev ,
& crev ) )
return ;
2009-06-05 14:42:42 +02:00
switch ( frev ) {
case 1 :
switch ( crev ) {
case 1 :
2010-01-19 17:32:27 -05:00
args . v1 . usPixelClock = cpu_to_le16 ( mode - > clock / 10 ) ;
args . v1 . usRefDiv = cpu_to_le16 ( ref_div ) ;
args . v1 . usFbDiv = cpu_to_le16 ( fb_div ) ;
args . v1 . ucFracFbDiv = frac_fb_div ;
args . v1 . ucPostDiv = post_div ;
2010-01-12 17:54:34 -05:00
args . v1 . ucPpll = radeon_crtc - > pll_id ;
2010-01-19 17:32:27 -05:00
args . v1 . ucCRTC = radeon_crtc - > crtc_id ;
args . v1 . ucRefDivSrc = 1 ;
2009-06-05 14:42:42 +02:00
break ;
case 2 :
2010-01-19 17:32:27 -05:00
args . v2 . usPixelClock = cpu_to_le16 ( mode - > clock / 10 ) ;
args . v2 . usRefDiv = cpu_to_le16 ( ref_div ) ;
args . v2 . usFbDiv = cpu_to_le16 ( fb_div ) ;
args . v2 . ucFracFbDiv = frac_fb_div ;
args . v2 . ucPostDiv = post_div ;
2010-01-12 17:54:34 -05:00
args . v2 . ucPpll = radeon_crtc - > pll_id ;
2010-01-19 17:32:27 -05:00
args . v2 . ucCRTC = radeon_crtc - > crtc_id ;
args . v2 . ucRefDivSrc = 1 ;
2009-06-05 14:42:42 +02:00
break ;
case 3 :
2010-01-19 17:32:27 -05:00
args . v3 . usPixelClock = cpu_to_le16 ( mode - > clock / 10 ) ;
args . v3 . usRefDiv = cpu_to_le16 ( ref_div ) ;
args . v3 . usFbDiv = cpu_to_le16 ( fb_div ) ;
args . v3 . ucFracFbDiv = frac_fb_div ;
args . v3 . ucPostDiv = post_div ;
2010-01-12 17:54:34 -05:00
args . v3 . ucPpll = radeon_crtc - > pll_id ;
args . v3 . ucMiscInfo = ( radeon_crtc - > pll_id < < 2 ) ;
2010-01-19 17:32:27 -05:00
args . v3 . ucTransmitterId = radeon_encoder - > encoder_id ;
2010-01-12 17:54:34 -05:00
args . v3 . ucEncoderMode = encoder_mode ;
break ;
case 5 :
args . v5 . ucCRTC = radeon_crtc - > crtc_id ;
args . v5 . usPixelClock = cpu_to_le16 ( mode - > clock / 10 ) ;
args . v5 . ucRefDiv = ref_div ;
args . v5 . usFbDiv = cpu_to_le16 ( fb_div ) ;
args . v5 . ulFbDivDecFrac = cpu_to_le32 ( frac_fb_div * 100000 ) ;
args . v5 . ucPostDiv = post_div ;
args . v5 . ucMiscInfo = 0 ; /* HDMI depth, etc. */
args . v5 . ucTransmitterID = radeon_encoder - > encoder_id ;
args . v5 . ucEncoderMode = encoder_mode ;
args . v5 . ucPpll = radeon_crtc - > pll_id ;
2009-06-05 14:42:42 +02:00
break ;
default :
DRM_ERROR ( " Unknown table version %d %d \n " , frev , crev ) ;
return ;
}
break ;
default :
DRM_ERROR ( " Unknown table version %d %d \n " , frev , crev ) ;
return ;
}
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
}
2010-01-12 17:54:34 -05:00
static int evergreen_crtc_set_base ( struct drm_crtc * crtc , int x , int y ,
struct drm_framebuffer * old_fb )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_framebuffer * radeon_fb ;
struct drm_gem_object * obj ;
struct radeon_bo * rbo ;
uint64_t fb_location ;
uint32_t fb_format , fb_pitch_pixels , tiling_flags ;
int r ;
/* no fb bound */
if ( ! crtc - > fb ) {
DRM_DEBUG ( " No FB bound \n " ) ;
return 0 ;
}
radeon_fb = to_radeon_framebuffer ( crtc - > fb ) ;
/* Pin framebuffer & get tilling informations */
obj = radeon_fb - > obj ;
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 , & fb_location ) ;
if ( unlikely ( r ! = 0 ) ) {
radeon_bo_unreserve ( rbo ) ;
return - EINVAL ;
}
radeon_bo_get_tiling_flags ( rbo , & tiling_flags , NULL ) ;
radeon_bo_unreserve ( rbo ) ;
switch ( crtc - > fb - > bits_per_pixel ) {
case 8 :
fb_format = ( EVERGREEN_GRPH_DEPTH ( EVERGREEN_GRPH_DEPTH_8BPP ) |
EVERGREEN_GRPH_FORMAT ( EVERGREEN_GRPH_FORMAT_INDEXED ) ) ;
break ;
case 15 :
fb_format = ( EVERGREEN_GRPH_DEPTH ( EVERGREEN_GRPH_DEPTH_16BPP ) |
EVERGREEN_GRPH_FORMAT ( EVERGREEN_GRPH_FORMAT_ARGB1555 ) ) ;
break ;
case 16 :
fb_format = ( EVERGREEN_GRPH_DEPTH ( EVERGREEN_GRPH_DEPTH_16BPP ) |
EVERGREEN_GRPH_FORMAT ( EVERGREEN_GRPH_FORMAT_ARGB565 ) ) ;
break ;
case 24 :
case 32 :
fb_format = ( EVERGREEN_GRPH_DEPTH ( EVERGREEN_GRPH_DEPTH_32BPP ) |
EVERGREEN_GRPH_FORMAT ( EVERGREEN_GRPH_FORMAT_ARGB8888 ) ) ;
break ;
default :
DRM_ERROR ( " Unsupported screen depth %d \n " ,
crtc - > fb - > bits_per_pixel ) ;
return - EINVAL ;
}
switch ( radeon_crtc - > crtc_id ) {
case 0 :
WREG32 ( AVIVO_D1VGA_CONTROL , 0 ) ;
break ;
case 1 :
WREG32 ( AVIVO_D2VGA_CONTROL , 0 ) ;
break ;
case 2 :
WREG32 ( EVERGREEN_D3VGA_CONTROL , 0 ) ;
break ;
case 3 :
WREG32 ( EVERGREEN_D4VGA_CONTROL , 0 ) ;
break ;
case 4 :
WREG32 ( EVERGREEN_D5VGA_CONTROL , 0 ) ;
break ;
case 5 :
WREG32 ( EVERGREEN_D6VGA_CONTROL , 0 ) ;
break ;
default :
break ;
}
WREG32 ( EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc - > crtc_offset ,
upper_32_bits ( fb_location ) ) ;
WREG32 ( EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc - > crtc_offset ,
upper_32_bits ( fb_location ) ) ;
WREG32 ( EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc - > crtc_offset ,
( u32 ) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK ) ;
WREG32 ( EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc - > crtc_offset ,
( u32 ) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK ) ;
WREG32 ( EVERGREEN_GRPH_CONTROL + radeon_crtc - > crtc_offset , fb_format ) ;
WREG32 ( EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( EVERGREEN_GRPH_X_START + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( EVERGREEN_GRPH_Y_START + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( EVERGREEN_GRPH_X_END + radeon_crtc - > crtc_offset , crtc - > fb - > width ) ;
WREG32 ( EVERGREEN_GRPH_Y_END + radeon_crtc - > crtc_offset , crtc - > fb - > height ) ;
fb_pitch_pixels = crtc - > fb - > pitch / ( crtc - > fb - > bits_per_pixel / 8 ) ;
WREG32 ( EVERGREEN_GRPH_PITCH + radeon_crtc - > crtc_offset , fb_pitch_pixels ) ;
WREG32 ( EVERGREEN_GRPH_ENABLE + radeon_crtc - > crtc_offset , 1 ) ;
WREG32 ( EVERGREEN_DESKTOP_HEIGHT + radeon_crtc - > crtc_offset ,
crtc - > mode . vdisplay ) ;
x & = ~ 3 ;
y & = ~ 1 ;
WREG32 ( EVERGREEN_VIEWPORT_START + radeon_crtc - > crtc_offset ,
( x < < 16 ) | y ) ;
WREG32 ( EVERGREEN_VIEWPORT_SIZE + radeon_crtc - > crtc_offset ,
( crtc - > mode . hdisplay < < 16 ) | crtc - > mode . vdisplay ) ;
if ( crtc - > mode . flags & DRM_MODE_FLAG_INTERLACE )
WREG32 ( EVERGREEN_DATA_FORMAT + radeon_crtc - > crtc_offset ,
EVERGREEN_INTERLEAVE_EN ) ;
else
WREG32 ( EVERGREEN_DATA_FORMAT + radeon_crtc - > crtc_offset , 0 ) ;
if ( old_fb & & old_fb ! = crtc - > fb ) {
radeon_fb = to_radeon_framebuffer ( old_fb ) ;
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 ) ;
}
/* Bytes per pixel may have changed */
radeon_bandwidth_update ( rdev ) ;
return 0 ;
}
2010-01-19 16:34:01 -05:00
static int avivo_crtc_set_base ( struct drm_crtc * crtc , int x , int y ,
struct drm_framebuffer * old_fb )
2009-06-05 14:42:42 +02:00
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_framebuffer * radeon_fb ;
struct drm_gem_object * obj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * rbo ;
2009-06-05 14:42:42 +02:00
uint64_t fb_location ;
2009-06-24 09:48:08 +10:00
uint32_t fb_format , fb_pitch_pixels , tiling_flags ;
2009-11-20 14:29:23 +01:00
int r ;
2009-06-05 14:42:42 +02:00
2009-11-17 14:08:55 -08:00
/* no fb bound */
if ( ! crtc - > fb ) {
DRM_DEBUG ( " No FB bound \n " ) ;
return 0 ;
}
2009-06-05 14:42:42 +02:00
radeon_fb = to_radeon_framebuffer ( crtc - > fb ) ;
2009-11-20 14:29:23 +01:00
/* Pin framebuffer & get tilling informations */
2009-06-05 14:42:42 +02:00
obj = radeon_fb - > obj ;
2009-11-20 14:29:23 +01: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 , & fb_location ) ;
if ( unlikely ( r ! = 0 ) ) {
radeon_bo_unreserve ( rbo ) ;
2009-06-05 14:42:42 +02:00
return - EINVAL ;
}
2009-11-20 14:29:23 +01:00
radeon_bo_get_tiling_flags ( rbo , & tiling_flags , NULL ) ;
radeon_bo_unreserve ( rbo ) ;
2009-06-05 14:42:42 +02:00
switch ( crtc - > fb - > bits_per_pixel ) {
2009-09-16 10:15:21 +10:00
case 8 :
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
AVIVO_D1GRPH_CONTROL_8BPP_INDEXED ;
break ;
2009-06-05 14:42:42 +02:00
case 15 :
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555 ;
break ;
case 16 :
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
AVIVO_D1GRPH_CONTROL_16BPP_RGB565 ;
break ;
case 24 :
case 32 :
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 ;
break ;
default :
DRM_ERROR ( " Unsupported screen depth %d \n " ,
crtc - > fb - > bits_per_pixel ) ;
return - EINVAL ;
}
2009-12-08 15:45:13 +10:00
if ( tiling_flags & RADEON_TILING_MACRO )
fb_format | = AVIVO_D1GRPH_MACRO_ADDRESS_MODE ;
2009-06-24 09:48:08 +10:00
if ( tiling_flags & RADEON_TILING_MICRO )
fb_format | = AVIVO_D1GRPH_TILED ;
2009-06-05 14:42:42 +02:00
if ( radeon_crtc - > crtc_id = = 0 )
WREG32 ( AVIVO_D1VGA_CONTROL , 0 ) ;
else
WREG32 ( AVIVO_D2VGA_CONTROL , 0 ) ;
2009-10-22 16:12:34 -04:00
if ( rdev - > family > = CHIP_RV770 ) {
if ( radeon_crtc - > crtc_id ) {
WREG32 ( R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH , 0 ) ;
WREG32 ( R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH , 0 ) ;
} else {
WREG32 ( R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH , 0 ) ;
WREG32 ( R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH , 0 ) ;
}
}
2009-06-05 14:42:42 +02:00
WREG32 ( AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc - > crtc_offset ,
( u32 ) fb_location ) ;
WREG32 ( AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
radeon_crtc - > crtc_offset , ( u32 ) fb_location ) ;
WREG32 ( AVIVO_D1GRPH_CONTROL + radeon_crtc - > crtc_offset , fb_format ) ;
WREG32 ( AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( AVIVO_D1GRPH_X_START + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( AVIVO_D1GRPH_Y_START + radeon_crtc - > crtc_offset , 0 ) ;
WREG32 ( AVIVO_D1GRPH_X_END + radeon_crtc - > crtc_offset , crtc - > fb - > width ) ;
WREG32 ( AVIVO_D1GRPH_Y_END + radeon_crtc - > crtc_offset , crtc - > fb - > height ) ;
fb_pitch_pixels = crtc - > fb - > pitch / ( crtc - > fb - > bits_per_pixel / 8 ) ;
WREG32 ( AVIVO_D1GRPH_PITCH + radeon_crtc - > crtc_offset , fb_pitch_pixels ) ;
WREG32 ( AVIVO_D1GRPH_ENABLE + radeon_crtc - > crtc_offset , 1 ) ;
WREG32 ( AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc - > crtc_offset ,
crtc - > mode . vdisplay ) ;
x & = ~ 3 ;
y & = ~ 1 ;
WREG32 ( AVIVO_D1MODE_VIEWPORT_START + radeon_crtc - > crtc_offset ,
( x < < 16 ) | y ) ;
WREG32 ( AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc - > crtc_offset ,
( crtc - > mode . hdisplay < < 16 ) | crtc - > mode . vdisplay ) ;
if ( crtc - > mode . flags & DRM_MODE_FLAG_INTERLACE )
WREG32 ( AVIVO_D1MODE_DATA_FORMAT + radeon_crtc - > crtc_offset ,
AVIVO_D1MODE_INTERLEAVE_EN ) ;
else
WREG32 ( AVIVO_D1MODE_DATA_FORMAT + radeon_crtc - > crtc_offset , 0 ) ;
if ( old_fb & & old_fb ! = crtc - > fb ) {
radeon_fb = to_radeon_framebuffer ( old_fb ) ;
2009-11-20 14:29:23 +01: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 14:42:42 +02:00
}
2009-10-08 10:44:09 +02:00
/* Bytes per pixel may have changed */
radeon_bandwidth_update ( rdev ) ;
2009-06-05 14:42:42 +02:00
return 0 ;
}
2010-01-19 16:34:01 -05:00
int atombios_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 ;
2010-01-12 17:54:34 -05:00
if ( ASIC_IS_DCE4 ( rdev ) )
return evergreen_crtc_set_base ( crtc , x , y , old_fb ) ;
else if ( ASIC_IS_AVIVO ( rdev ) )
2010-01-19 16:34:01 -05:00
return avivo_crtc_set_base ( crtc , x , y , old_fb ) ;
else
return radeon_crtc_set_base ( crtc , x , y , old_fb ) ;
}
2010-01-20 16:22:53 -05:00
/* properly set additional regs when using atombios */
static void radeon_legacy_atom_fixup ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
u32 disp_merge_cntl ;
switch ( radeon_crtc - > crtc_id ) {
case 0 :
disp_merge_cntl = RREG32 ( RADEON_DISP_MERGE_CNTL ) ;
disp_merge_cntl & = ~ RADEON_DISP_RGB_OFFSET_EN ;
WREG32 ( RADEON_DISP_MERGE_CNTL , disp_merge_cntl ) ;
break ;
case 1 :
disp_merge_cntl = RREG32 ( RADEON_DISP2_MERGE_CNTL ) ;
disp_merge_cntl & = ~ RADEON_DISP2_RGB_OFFSET_EN ;
WREG32 ( RADEON_DISP2_MERGE_CNTL , disp_merge_cntl ) ;
WREG32 ( RADEON_FP_H2_SYNC_STRT_WID , RREG32 ( RADEON_CRTC2_H_SYNC_STRT_WID ) ) ;
WREG32 ( RADEON_FP_V2_SYNC_STRT_WID , RREG32 ( RADEON_CRTC2_V_SYNC_STRT_WID ) ) ;
break ;
}
}
2010-01-12 17:54:34 -05:00
static int radeon_atom_pick_pll ( struct drm_crtc * crtc )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
struct drm_encoder * test_encoder ;
struct drm_crtc * test_crtc ;
uint32_t pll_in_use = 0 ;
if ( ASIC_IS_DCE4 ( rdev ) ) {
/* if crtc is driving DP and we have an ext clock, use that */
list_for_each_entry ( test_encoder , & dev - > mode_config . encoder_list , head ) {
if ( test_encoder - > crtc & & ( test_encoder - > crtc = = crtc ) ) {
if ( atombios_get_encoder_mode ( test_encoder ) = = ATOM_ENCODER_MODE_DP ) {
if ( rdev - > clock . dp_extclk )
return ATOM_PPLL_INVALID ;
}
}
}
/* otherwise, pick one of the plls */
list_for_each_entry ( test_crtc , & dev - > mode_config . crtc_list , head ) {
struct radeon_crtc * radeon_test_crtc ;
if ( crtc = = test_crtc )
continue ;
radeon_test_crtc = to_radeon_crtc ( test_crtc ) ;
if ( ( radeon_test_crtc - > pll_id > = ATOM_PPLL1 ) & &
( radeon_test_crtc - > pll_id < = ATOM_PPLL2 ) )
pll_in_use | = ( 1 < < radeon_test_crtc - > pll_id ) ;
}
if ( ! ( pll_in_use & 1 ) )
return ATOM_PPLL1 ;
return ATOM_PPLL2 ;
} else
return radeon_crtc - > crtc_id ;
}
2009-06-05 14:42:42 +02:00
int atombios_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 )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
/* TODO color tiling */
2010-03-06 10:57:30 -05:00
atombios_disable_ss ( crtc ) ;
2010-01-12 17:54:34 -05:00
/* always set DCPLL */
if ( ASIC_IS_DCE4 ( rdev ) )
atombios_crtc_set_dcpll ( crtc ) ;
2009-06-05 14:42:42 +02:00
atombios_crtc_set_pll ( crtc , adjusted_mode ) ;
2010-03-06 10:57:30 -05:00
atombios_enable_ss ( crtc ) ;
2009-06-05 14:42:42 +02:00
2010-01-12 17:54:34 -05:00
if ( ASIC_IS_DCE4 ( rdev ) )
atombios_set_crtc_dtd_timing ( crtc , adjusted_mode ) ;
else if ( ASIC_IS_AVIVO ( rdev ) )
atombios_crtc_set_timing ( crtc , adjusted_mode ) ;
2009-06-05 14:42:42 +02:00
else {
2010-01-12 17:54:34 -05:00
atombios_crtc_set_timing ( crtc , adjusted_mode ) ;
2009-10-08 15:09:31 -04:00
if ( radeon_crtc - > crtc_id = = 0 )
atombios_set_crtc_dtd_timing ( crtc , adjusted_mode ) ;
2010-01-20 16:22:53 -05:00
radeon_legacy_atom_fixup ( crtc ) ;
2009-06-05 14:42:42 +02:00
}
2010-01-12 17:54:34 -05:00
atombios_crtc_set_base ( crtc , x , y , old_fb ) ;
2009-07-13 21:04:08 +02:00
atombios_overscan_setup ( crtc , mode , adjusted_mode ) ;
atombios_scaler_setup ( crtc ) ;
2009-06-05 14:42:42 +02:00
return 0 ;
}
static bool atombios_crtc_mode_fixup ( struct drm_crtc * crtc ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
2010-03-16 17:42:46 -04:00
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
/* adjust pm to upcoming mode change */
radeon_pm_compute_clocks ( rdev ) ;
2009-07-13 21:04:08 +02:00
if ( ! radeon_crtc_scaling_mode_fixup ( crtc , mode , adjusted_mode ) )
return false ;
2009-06-05 14:42:42 +02:00
return true ;
}
static void atombios_crtc_prepare ( struct drm_crtc * crtc )
{
2010-03-08 17:10:41 -05:00
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
/* pick pll */
radeon_crtc - > pll_id = radeon_atom_pick_pll ( crtc ) ;
2010-02-09 12:04:43 -05:00
atombios_lock_crtc ( crtc , ATOM_ENABLE ) ;
2010-01-21 16:50:30 -05:00
atombios_crtc_dpms ( crtc , DRM_MODE_DPMS_OFF ) ;
2009-06-05 14:42:42 +02:00
}
static void atombios_crtc_commit ( struct drm_crtc * crtc )
{
atombios_crtc_dpms ( crtc , DRM_MODE_DPMS_ON ) ;
2010-02-09 12:04:43 -05:00
atombios_lock_crtc ( crtc , ATOM_DISABLE ) ;
2009-06-05 14:42:42 +02:00
}
static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
. dpms = atombios_crtc_dpms ,
. mode_fixup = atombios_crtc_mode_fixup ,
. mode_set = atombios_crtc_mode_set ,
. mode_set_base = atombios_crtc_set_base ,
. prepare = atombios_crtc_prepare ,
. commit = atombios_crtc_commit ,
2009-10-05 09:58:02 +10:00
. load_lut = radeon_crtc_load_lut ,
2009-06-05 14:42:42 +02:00
} ;
void radeon_atombios_init_crtc ( struct drm_device * dev ,
struct radeon_crtc * radeon_crtc )
{
2010-01-12 17:54:34 -05:00
struct radeon_device * rdev = dev - > dev_private ;
if ( ASIC_IS_DCE4 ( rdev ) ) {
switch ( radeon_crtc - > crtc_id ) {
case 0 :
default :
2010-02-09 17:18:48 -05:00
radeon_crtc - > crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET ;
2010-01-12 17:54:34 -05:00
break ;
case 1 :
2010-02-09 17:18:48 -05:00
radeon_crtc - > crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET ;
2010-01-12 17:54:34 -05:00
break ;
case 2 :
2010-02-09 17:18:48 -05:00
radeon_crtc - > crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET ;
2010-01-12 17:54:34 -05:00
break ;
case 3 :
2010-02-09 17:18:48 -05:00
radeon_crtc - > crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET ;
2010-01-12 17:54:34 -05:00
break ;
case 4 :
2010-02-09 17:18:48 -05:00
radeon_crtc - > crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET ;
2010-01-12 17:54:34 -05:00
break ;
case 5 :
2010-02-09 17:18:48 -05:00
radeon_crtc - > crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET ;
2010-01-12 17:54:34 -05:00
break ;
}
} else {
if ( radeon_crtc - > crtc_id = = 1 )
radeon_crtc - > crtc_offset =
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL ;
else
radeon_crtc - > crtc_offset = 0 ;
}
radeon_crtc - > pll_id = - 1 ;
2009-06-05 14:42:42 +02:00
drm_crtc_helper_add ( & radeon_crtc - > base , & atombios_helper_funcs ) ;
}