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 . 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 ;
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 ;
}
break ;
case RMX_FULL :
default :
2010-08-03 19:59:20 -04:00
args . usOverscanRight = radeon_crtc - > h_border ;
args . usOverscanLeft = radeon_crtc - > h_border ;
args . usOverscanBottom = radeon_crtc - > v_border ;
args . usOverscanTop = radeon_crtc - > v_border ;
2009-07-13 21:04:08 +02:00
break ;
}
2010-08-03 19:59:20 -04:00
atom_execute_table ( rdev - > mode_info . atom_context , index , ( uint32_t * ) & args ) ;
2009-07-13 21:04:08 +02:00
}
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-12-20 11:22:29 -05:00
if ( radeon_crtc - > enabled )
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 ) ) ;
2010-08-03 19:59:20 -04:00
args . usH_Size = cpu_to_le16 ( mode - > crtc_hdisplay - ( radeon_crtc - > h_border * 2 ) ) ;
2009-10-08 15:09:31 -04:00
args . usH_Blanking_Time =
2010-08-03 19:59:20 -04:00
cpu_to_le16 ( mode - > crtc_hblank_end - mode - > crtc_hdisplay + ( radeon_crtc - > h_border * 2 ) ) ;
args . usV_Size = cpu_to_le16 ( mode - > crtc_vdisplay - ( radeon_crtc - > v_border * 2 ) ) ;
2009-10-08 15:09:31 -04:00
args . usV_Blanking_Time =
2010-08-03 19:59:20 -04:00
cpu_to_le16 ( mode - > crtc_vblank_end - mode - > crtc_vdisplay + ( radeon_crtc - > v_border * 2 ) ) ;
2009-10-08 15:09:31 -04:00
args . usH_SyncOffset =
2010-08-03 19:59:20 -04:00
cpu_to_le16 ( mode - > crtc_hsync_start - mode - > crtc_hdisplay + radeon_crtc - > h_border ) ;
2009-10-08 15:09:31 -04:00
args . usH_SyncWidth =
cpu_to_le16 ( mode - > crtc_hsync_end - mode - > crtc_hsync_start ) ;
args . usV_SyncOffset =
2010-08-03 19:59:20 -04:00
cpu_to_le16 ( mode - > crtc_vsync_start - mode - > crtc_vdisplay + radeon_crtc - > v_border ) ;
2009-10-08 15:09:31 -04:00
args . usV_SyncWidth =
cpu_to_le16 ( mode - > crtc_vsync_end - mode - > crtc_vsync_start ) ;
2010-08-03 19:59:20 -04:00
args . ucH_Border = radeon_crtc - > h_border ;
args . ucV_Border = radeon_crtc - > v_border ;
2009-10-08 15:09:31 -04:00
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 ) ;
2010-09-03 15:52:53 -04:00
args . ucOverscanRight = radeon_crtc - > h_border ;
args . ucOverscanLeft = radeon_crtc - > h_border ;
args . ucOverscanBottom = radeon_crtc - > v_border ;
args . ucOverscanTop = radeon_crtc - > v_border ;
2009-10-08 15:09:31 -04:00
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 {
2010-10-04 17:13:01 -04:00
ENABLE_LVDS_SS_PARAMETERS lvds_ss ;
ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2 ;
2010-02-01 16:39:11 -05:00
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1 ;
2010-10-04 17:13:01 -04:00
ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2 ;
2011-01-06 21:19:16 -05:00
ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3 ;
2010-02-01 16:39:11 -05:00
} ;
2010-10-04 17:13:01 -04:00
static void atombios_crtc_program_ss ( struct drm_crtc * crtc ,
int enable ,
int pll_id ,
struct radeon_atom_ss * ss )
2009-10-16 11:15:25 -04:00
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
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
2010-10-04 17:13:01 -04:00
memset ( & args , 0 , sizeof ( args ) ) ;
2010-01-12 17:54:34 -05:00
2011-01-06 21:19:16 -05:00
if ( ASIC_IS_DCE5 ( rdev ) ) {
args . v3 . usSpreadSpectrumAmountFrac = 0 ;
args . v3 . ucSpreadSpectrumType = ss - > type ;
switch ( pll_id ) {
case ATOM_PPLL1 :
args . v3 . ucSpreadSpectrumType | = ATOM_PPLL_SS_TYPE_V3_P1PLL ;
args . v3 . usSpreadSpectrumAmount = ss - > amount ;
args . v3 . usSpreadSpectrumStep = ss - > step ;
break ;
case ATOM_PPLL2 :
args . v3 . ucSpreadSpectrumType | = ATOM_PPLL_SS_TYPE_V3_P2PLL ;
args . v3 . usSpreadSpectrumAmount = ss - > amount ;
args . v3 . usSpreadSpectrumStep = ss - > step ;
break ;
case ATOM_DCPLL :
args . v3 . ucSpreadSpectrumType | = ATOM_PPLL_SS_TYPE_V3_DCPLL ;
args . v3 . usSpreadSpectrumAmount = 0 ;
args . v3 . usSpreadSpectrumStep = 0 ;
break ;
case ATOM_PPLL_INVALID :
return ;
}
args . v2 . ucEnable = enable ;
} else if ( ASIC_IS_DCE4 ( rdev ) ) {
2010-10-04 17:13:01 -04:00
args . v2 . usSpreadSpectrumPercentage = cpu_to_le16 ( ss - > percentage ) ;
args . v2 . ucSpreadSpectrumType = ss - > type ;
switch ( pll_id ) {
case ATOM_PPLL1 :
args . v2 . ucSpreadSpectrumType | = ATOM_PPLL_SS_TYPE_V2_P1PLL ;
args . v2 . usSpreadSpectrumAmount = ss - > amount ;
args . v2 . usSpreadSpectrumStep = ss - > step ;
break ;
case ATOM_PPLL2 :
args . v2 . ucSpreadSpectrumType | = ATOM_PPLL_SS_TYPE_V2_P2PLL ;
args . v2 . usSpreadSpectrumAmount = ss - > amount ;
args . v2 . usSpreadSpectrumStep = ss - > step ;
2009-10-16 11:15:25 -04:00
break ;
2010-10-04 17:13:01 -04:00
case ATOM_DCPLL :
args . v2 . ucSpreadSpectrumType | = ATOM_PPLL_SS_TYPE_V2_DCPLL ;
args . v2 . usSpreadSpectrumAmount = 0 ;
args . v2 . usSpreadSpectrumStep = 0 ;
break ;
case ATOM_PPLL_INVALID :
return ;
2009-10-16 11:15:25 -04:00
}
2010-10-04 17:13:01 -04:00
args . v2 . ucEnable = enable ;
} else if ( ASIC_IS_DCE3 ( rdev ) ) {
args . v1 . usSpreadSpectrumPercentage = cpu_to_le16 ( ss - > percentage ) ;
args . v1 . ucSpreadSpectrumType = ss - > type ;
args . v1 . ucSpreadSpectrumStep = ss - > step ;
args . v1 . ucSpreadSpectrumDelay = ss - > delay ;
args . v1 . ucSpreadSpectrumRange = ss - > range ;
args . v1 . ucPpll = pll_id ;
args . v1 . ucEnable = enable ;
} else if ( ASIC_IS_AVIVO ( rdev ) ) {
if ( enable = = ATOM_DISABLE ) {
atombios_disable_ss ( crtc ) ;
return ;
}
args . lvds_ss_2 . usSpreadSpectrumPercentage = cpu_to_le16 ( ss - > percentage ) ;
args . lvds_ss_2 . ucSpreadSpectrumType = ss - > type ;
args . lvds_ss_2 . ucSpreadSpectrumStep = ss - > step ;
args . lvds_ss_2 . ucSpreadSpectrumDelay = ss - > delay ;
args . lvds_ss_2 . ucSpreadSpectrumRange = ss - > range ;
args . lvds_ss_2 . ucEnable = enable ;
2009-10-16 11:15:25 -04:00
} else {
2010-10-04 17:13:01 -04:00
if ( enable = = ATOM_DISABLE ) {
atombios_disable_ss ( crtc ) ;
return ;
}
args . lvds_ss . usSpreadSpectrumPercentage = cpu_to_le16 ( ss - > percentage ) ;
args . lvds_ss . ucSpreadSpectrumType = ss - > type ;
args . lvds_ss . ucSpreadSpectrumStepSize_Delay = ( ss - > step & 3 ) < < 2 ;
args . lvds_ss . ucSpreadSpectrumStepSize_Delay | = ( ss - > delay & 7 ) < < 4 ;
args . lvds_ss . ucEnable = 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 ,
2010-10-04 17:13:01 -04:00
struct radeon_pll * pll ,
bool ss_enabled ,
struct radeon_atom_ss * ss )
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-08-16 12:44:47 -04:00
u32 dp_clock = mode - > clock ;
int bpc = 8 ;
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
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-06-08 19:44:36 -04:00
pll - > flags | = ( /*RADEON_PLL_USE_FRAC_FB_DIV |*/
2010-01-19 17:16:10 -05:00
RADEON_PLL_PREFER_CLOSEST_LOWER ) ;
2010-10-19 10:36:47 +10:00
if ( ASIC_IS_DCE32 ( rdev ) & & mode - > clock > 200000 ) /* range limits??? */
pll - > flags | = RADEON_PLL_PREFER_HIGH_FB_DIV ;
else
pll - > flags | = RADEON_PLL_PREFER_LOW_REF_DIV ;
} else {
2010-01-19 17:16:10 -05:00
pll - > flags | = RADEON_PLL_LEGACY ;
2009-06-05 14:42:42 +02:00
2010-10-19 10:36:47 +10:00
if ( mode - > clock > 200000 ) /* range limits??? */
pll - > flags | = RADEON_PLL_PREFER_HIGH_FB_DIV ;
else
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-08-16 12:44:47 -04:00
if ( radeon_encoder - > devices & ( ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT ) ) {
struct drm_connector * connector = radeon_get_connector_for_encoder ( encoder ) ;
if ( connector ) {
struct radeon_connector * radeon_connector = to_radeon_connector ( connector ) ;
struct radeon_connector_atom_dig * dig_connector =
radeon_connector - > con_priv ;
dp_clock = dig_connector - > dp_clock ;
}
}
2011-01-31 16:48:53 -05:00
/* this might work properly with the new pll algo */
2010-12-12 23:27:23 -05:00
#if 0 /* doesn't work properly on some laptops */
2010-10-04 17:13:01 -04:00
/* use recommended ref_div for ss */
if ( radeon_encoder - > devices & ( ATOM_DEVICE_LCD_SUPPORT ) ) {
if ( ss_enabled ) {
if ( ss - > refdiv ) {
pll - > flags | = RADEON_PLL_USE_REF_DIV ;
pll - > reference_div = ss - > refdiv ;
}
}
}
2010-12-12 23:27:23 -05:00
# endif
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-09-29 11:37:41 -04:00
if ( radeon_encoder - > active_device & ( ATOM_DEVICE_TV_SUPPORT ) )
2010-04-09 15:31:56 -04:00
pll - > flags | = RADEON_PLL_PREFER_CLOSEST_LOWER ;
2011-01-31 16:48:53 -05:00
/* rv515 needs more testing with this option */
if ( rdev - > family ! = CHIP_RV515 ) {
if ( radeon_encoder - > devices & ( ATOM_DEVICE_LCD_SUPPORT ) )
pll - > flags | = RADEON_PLL_IS_LCD ;
}
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 ;
2011-01-20 23:35:58 +00:00
if ( ss_enabled )
2010-08-16 12:44:47 -04:00
args . v1 . ucConfig | =
ADJUST_DISPLAY_CONFIG_SS_ENABLE ;
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 ;
2011-01-20 23:35:58 +00:00
if ( ss_enabled )
args . v3 . sInput . ucDispPllConfig | =
DISPPLL_CONFIG_SS_ENABLE ;
2010-01-12 17:54:34 -05:00
if ( radeon_encoder - > devices & ( ATOM_DEVICE_DFP_SUPPORT ) ) {
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
2010-08-16 12:44:47 -04:00
if ( encoder_mode = = ATOM_ENCODER_MODE_DP ) {
2010-01-12 17:54:34 -05:00
args . v3 . sInput . ucDispPllConfig | =
DISPPLL_CONFIG_COHERENT_MODE ;
2010-08-16 12:44:47 -04:00
/* 16200 or 27000 */
args . v3 . sInput . usPixelClock = cpu_to_le16 ( dp_clock / 10 ) ;
} else {
if ( encoder_mode = = ATOM_ENCODER_MODE_HDMI ) {
/* deep color support */
args . v3 . sInput . usPixelClock =
cpu_to_le16 ( ( mode - > clock * bpc / 8 ) / 10 ) ;
}
2010-01-12 17:54:34 -05:00
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 ) ) {
2010-08-16 12:44:47 -04:00
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 ;
2010-08-16 12:44:47 -04:00
/* 16200 or 27000 */
args . v3 . sInput . usPixelClock = cpu_to_le16 ( dp_clock / 10 ) ;
2011-01-20 23:35:58 +00:00
} else if ( encoder_mode ! = ATOM_ENCODER_MODE_LVDS ) {
2010-03-29 21:37:08 -04:00
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 ;
2011-01-06 21:19:15 -05:00
PIXEL_CLOCK_PARAMETERS_V6 v6 ;
2010-01-19 17:32:27 -05:00
} ;
2011-01-06 21:19:15 -05:00
/* on DCE5, make sure the voltage is high enough to support the
* required disp clk .
*/
static void atombios_crtc_set_dcpll ( struct drm_crtc * crtc ,
u32 dispclk )
2010-01-12 17:54:34 -05:00
{
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 ;
2011-01-06 21:19:15 -05:00
args . v5 . usPixelClock = dispclk ;
2010-01-12 17:54:34 -05:00
args . v5 . ucPpll = ATOM_DCPLL ;
break ;
2011-01-06 21:19:15 -05:00
case 6 :
/* if the default dcpll clock is specified,
* SetPixelClock provides the dividers
*/
args . v6 . ulDispEngClkFreq = dispclk ;
args . v6 . ucPpll = ATOM_DCPLL ;
break ;
2010-01-12 17:54:34 -05:00
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-06-11 17:58:38 -04:00
static void atombios_crtc_program_pll ( struct drm_crtc * crtc ,
int crtc_id ,
int pll_id ,
u32 encoder_mode ,
u32 encoder_id ,
u32 clock ,
u32 ref_div ,
u32 fb_div ,
u32 frac_fb_div ,
u32 post_div )
2010-01-19 17:32:27 -05:00
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
u8 frev , crev ;
2010-06-11 17:58:38 -04:00
int index = GetIndexIntoMasterTable ( COMMAND , SetPixelClock ) ;
2010-01-19 17:32:27 -05:00
union set_pixel_clock args ;
memset ( & args , 0 , sizeof ( args ) ) ;
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-06-11 17:58:38 -04:00
if ( clock = = ATOM_DISABLE )
return ;
args . v1 . usPixelClock = cpu_to_le16 ( clock / 10 ) ;
2010-01-19 17:32:27 -05:00
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-06-11 17:58:38 -04:00
args . v1 . ucPpll = pll_id ;
args . v1 . ucCRTC = crtc_id ;
2010-01-19 17:32:27 -05:00
args . v1 . ucRefDivSrc = 1 ;
2009-06-05 14:42:42 +02:00
break ;
case 2 :
2010-06-11 17:58:38 -04:00
args . v2 . usPixelClock = cpu_to_le16 ( clock / 10 ) ;
2010-01-19 17:32:27 -05:00
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-06-11 17:58:38 -04:00
args . v2 . ucPpll = pll_id ;
args . v2 . ucCRTC = crtc_id ;
2010-01-19 17:32:27 -05:00
args . v2 . ucRefDivSrc = 1 ;
2009-06-05 14:42:42 +02:00
break ;
case 3 :
2010-06-11 17:58:38 -04:00
args . v3 . usPixelClock = cpu_to_le16 ( clock / 10 ) ;
2010-01-19 17:32:27 -05:00
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-06-11 17:58:38 -04:00
args . v3 . ucPpll = pll_id ;
args . v3 . ucMiscInfo = ( pll_id < < 2 ) ;
args . v3 . ucTransmitterId = encoder_id ;
2010-01-12 17:54:34 -05:00
args . v3 . ucEncoderMode = encoder_mode ;
break ;
case 5 :
2010-06-11 17:58:38 -04:00
args . v5 . ucCRTC = crtc_id ;
args . v5 . usPixelClock = cpu_to_le16 ( clock / 10 ) ;
2010-01-12 17:54:34 -05:00
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. */
2010-06-11 17:58:38 -04:00
args . v5 . ucTransmitterID = encoder_id ;
2010-01-12 17:54:34 -05:00
args . v5 . ucEncoderMode = encoder_mode ;
2010-06-11 17:58:38 -04:00
args . v5 . ucPpll = pll_id ;
2009-06-05 14:42:42 +02:00
break ;
2011-01-06 21:19:15 -05:00
case 6 :
args . v6 . ulCrtcPclkFreq . ucCRTC = crtc_id ;
args . v6 . ulCrtcPclkFreq . ulPixelClock = cpu_to_le32 ( clock / 10 ) ;
args . v6 . ucRefDiv = ref_div ;
args . v6 . usFbDiv = cpu_to_le16 ( fb_div ) ;
args . v6 . ulFbDivDecFrac = cpu_to_le32 ( frac_fb_div * 100000 ) ;
args . v6 . ucPostDiv = post_div ;
args . v6 . ucMiscInfo = 0 ; /* HDMI depth, etc. */
args . v6 . ucTransmitterID = encoder_id ;
args . v6 . ucEncoderMode = encoder_mode ;
args . v6 . ucPpll = pll_id ;
break ;
2009-06-05 14:42:42 +02:00
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-06-11 17:58:38 -04:00
static void atombios_crtc_set_pll ( struct drm_crtc * crtc , struct drm_display_mode * mode )
{
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 ;
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 ;
int encoder_mode = 0 ;
2010-10-04 17:13:01 -04:00
struct radeon_atom_ss ss ;
bool ss_enabled = false ;
2010-06-11 17:58:38 -04:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
if ( encoder - > crtc = = crtc ) {
radeon_encoder = to_radeon_encoder ( encoder ) ;
encoder_mode = atombios_get_encoder_mode ( encoder ) ;
break ;
}
}
if ( ! radeon_encoder )
return ;
switch ( radeon_crtc - > pll_id ) {
case ATOM_PPLL1 :
pll = & rdev - > clock . p1pll ;
break ;
case ATOM_PPLL2 :
pll = & rdev - > clock . p2pll ;
break ;
case ATOM_DCPLL :
case ATOM_PPLL_INVALID :
default :
pll = & rdev - > clock . dcpll ;
break ;
}
2010-10-04 17:13:01 -04:00
if ( radeon_encoder - > active_device &
( ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT ) ) {
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
struct drm_connector * connector =
radeon_get_connector_for_encoder ( encoder ) ;
struct radeon_connector * radeon_connector =
to_radeon_connector ( connector ) ;
struct radeon_connector_atom_dig * dig_connector =
radeon_connector - > con_priv ;
int dp_clock ;
switch ( encoder_mode ) {
case ATOM_ENCODER_MODE_DP :
/* DP/eDP */
dp_clock = dig_connector - > dp_clock / 10 ;
if ( radeon_encoder - > active_device & ( ATOM_DEVICE_LCD_SUPPORT ) ) {
if ( ASIC_IS_DCE4 ( rdev ) )
ss_enabled =
radeon_atombios_get_asic_ss_info ( rdev , & ss ,
dig - > lcd_ss_id ,
dp_clock ) ;
else
ss_enabled =
radeon_atombios_get_ppll_ss_info ( rdev , & ss ,
dig - > lcd_ss_id ) ;
} else {
if ( ASIC_IS_DCE4 ( rdev ) )
ss_enabled =
radeon_atombios_get_asic_ss_info ( rdev , & ss ,
ASIC_INTERNAL_SS_ON_DP ,
dp_clock ) ;
else {
if ( dp_clock = = 16200 ) {
ss_enabled =
radeon_atombios_get_ppll_ss_info ( rdev , & ss ,
ATOM_DP_SS_ID2 ) ;
if ( ! ss_enabled )
ss_enabled =
radeon_atombios_get_ppll_ss_info ( rdev , & ss ,
ATOM_DP_SS_ID1 ) ;
} else
ss_enabled =
radeon_atombios_get_ppll_ss_info ( rdev , & ss ,
ATOM_DP_SS_ID1 ) ;
}
}
break ;
case ATOM_ENCODER_MODE_LVDS :
if ( ASIC_IS_DCE4 ( rdev ) )
ss_enabled = radeon_atombios_get_asic_ss_info ( rdev , & ss ,
dig - > lcd_ss_id ,
mode - > clock / 10 ) ;
else
ss_enabled = radeon_atombios_get_ppll_ss_info ( rdev , & ss ,
dig - > lcd_ss_id ) ;
break ;
case ATOM_ENCODER_MODE_DVI :
if ( ASIC_IS_DCE4 ( rdev ) )
ss_enabled =
radeon_atombios_get_asic_ss_info ( rdev , & ss ,
ASIC_INTERNAL_SS_ON_TMDS ,
mode - > clock / 10 ) ;
break ;
case ATOM_ENCODER_MODE_HDMI :
if ( ASIC_IS_DCE4 ( rdev ) )
ss_enabled =
radeon_atombios_get_asic_ss_info ( rdev , & ss ,
ASIC_INTERNAL_SS_ON_HDMI ,
mode - > clock / 10 ) ;
break ;
default :
break ;
}
}
2010-06-11 17:58:38 -04:00
/* adjust pixel clock as needed */
2010-10-04 17:13:01 -04:00
adjusted_clock = atombios_adjust_pll ( crtc , mode , pll , ss_enabled , & ss ) ;
2010-06-11 17:58:38 -04:00
2011-01-31 16:48:53 -05:00
/* rv515 seems happier with the old algo */
if ( rdev - > family = = CHIP_RV515 )
radeon_compute_pll_legacy ( pll , adjusted_clock , & pll_clock , & fb_div , & frac_fb_div ,
& ref_div , & post_div ) ;
else if ( ASIC_IS_AVIVO ( rdev ) )
radeon_compute_pll_avivo ( pll , adjusted_clock , & pll_clock , & fb_div , & frac_fb_div ,
& ref_div , & post_div ) ;
else
radeon_compute_pll_legacy ( pll , adjusted_clock , & pll_clock , & fb_div , & frac_fb_div ,
& ref_div , & post_div ) ;
2010-06-11 17:58:38 -04:00
2010-10-04 17:13:01 -04:00
atombios_crtc_program_ss ( crtc , ATOM_DISABLE , radeon_crtc - > pll_id , & ss ) ;
2010-06-11 17:58:38 -04:00
atombios_crtc_program_pll ( crtc , radeon_crtc - > crtc_id , radeon_crtc - > pll_id ,
encoder_mode , radeon_encoder - > encoder_id , mode - > clock ,
ref_div , fb_div , frac_fb_div , post_div ) ;
2010-10-04 17:13:01 -04:00
if ( ss_enabled ) {
/* calculate ss amount and step size */
if ( ASIC_IS_DCE4 ( rdev ) ) {
u32 step_size ;
u32 amount = ( ( ( fb_div * 10 ) + frac_fb_div ) * ss . percentage ) / 10000 ;
ss . amount = ( amount / 10 ) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK ;
ss . amount | = ( ( amount - ( ss . amount * 10 ) ) < < ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT ) &
ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK ;
if ( ss . type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD )
step_size = ( 4 * amount * ref_div * ( ss . rate * 2048 ) ) /
( 125 * 25 * pll - > reference_freq / 100 ) ;
else
step_size = ( 2 * amount * ref_div * ( ss . rate * 2048 ) ) /
( 125 * 25 * pll - > reference_freq / 100 ) ;
ss . step = step_size ;
}
atombios_crtc_program_ss ( crtc , ATOM_ENABLE , radeon_crtc - > pll_id , & ss ) ;
}
2010-06-11 17:58:38 -04:00
}
2010-09-26 06:47:23 -05:00
static int evergreen_crtc_do_set_base ( struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
int x , int y , int atomic )
2010-01-12 17:54:34 -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 radeon_framebuffer * radeon_fb ;
2010-09-26 06:47:23 -05:00
struct drm_framebuffer * target_fb ;
2010-01-12 17:54:34 -05:00
struct drm_gem_object * obj ;
struct radeon_bo * rbo ;
uint64_t fb_location ;
uint32_t fb_format , fb_pitch_pixels , tiling_flags ;
2011-01-25 11:55:50 -05:00
u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP ( EVERGREEN_GRPH_ENDIAN_NONE ) ;
2010-01-12 17:54:34 -05:00
int r ;
/* no fb bound */
2010-09-26 06:47:23 -05:00
if ( ! atomic & & ! crtc - > fb ) {
2010-08-02 10:42:55 +10:00
DRM_DEBUG_KMS ( " No FB bound \n " ) ;
2010-01-12 17:54:34 -05:00
return 0 ;
}
2010-09-26 06:47:23 -05:00
if ( atomic ) {
radeon_fb = to_radeon_framebuffer ( fb ) ;
target_fb = fb ;
}
else {
radeon_fb = to_radeon_framebuffer ( crtc - > fb ) ;
target_fb = crtc - > fb ;
}
2010-01-12 17:54:34 -05:00
2010-09-26 06:47:23 -05:00
/* If atomic, assume fb object is pinned & idle & fenced and
* just update base pointers
*/
2010-01-12 17:54:34 -05:00
obj = radeon_fb - > obj ;
rbo = obj - > driver_private ;
r = radeon_bo_reserve ( rbo , false ) ;
if ( unlikely ( r ! = 0 ) )
return r ;
2010-09-26 06:47:23 -05:00
if ( atomic )
fb_location = radeon_bo_gpu_offset ( rbo ) ;
else {
r = radeon_bo_pin ( rbo , RADEON_GEM_DOMAIN_VRAM , & fb_location ) ;
if ( unlikely ( r ! = 0 ) ) {
radeon_bo_unreserve ( rbo ) ;
return - EINVAL ;
}
2010-01-12 17:54:34 -05:00
}
2010-09-26 06:47:23 -05:00
2010-01-12 17:54:34 -05:00
radeon_bo_get_tiling_flags ( rbo , & tiling_flags , NULL ) ;
radeon_bo_unreserve ( rbo ) ;
2010-09-26 06:47:23 -05:00
switch ( target_fb - > bits_per_pixel ) {
2010-01-12 17:54:34 -05:00
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 ) ) ;
2011-01-25 11:55:50 -05:00
# ifdef __BIG_ENDIAN
fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP ( EVERGREEN_GRPH_ENDIAN_8IN16 ) ;
# endif
2010-01-12 17:54:34 -05:00
break ;
case 24 :
case 32 :
fb_format = ( EVERGREEN_GRPH_DEPTH ( EVERGREEN_GRPH_DEPTH_32BPP ) |
EVERGREEN_GRPH_FORMAT ( EVERGREEN_GRPH_FORMAT_ARGB8888 ) ) ;
2011-01-25 11:55:50 -05:00
# ifdef __BIG_ENDIAN
fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP ( EVERGREEN_GRPH_ENDIAN_8IN32 ) ;
# endif
2010-01-12 17:54:34 -05:00
break ;
default :
DRM_ERROR ( " Unsupported screen depth %d \n " ,
2010-09-26 06:47:23 -05:00
target_fb - > bits_per_pixel ) ;
2010-01-12 17:54:34 -05:00
return - EINVAL ;
}
2010-05-20 12:12:48 -04:00
if ( tiling_flags & RADEON_TILING_MACRO )
fb_format | = EVERGREEN_GRPH_ARRAY_MODE ( EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1 ) ;
else if ( tiling_flags & RADEON_TILING_MICRO )
fb_format | = EVERGREEN_GRPH_ARRAY_MODE ( EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1 ) ;
2010-01-12 17:54:34 -05:00
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 ) ;
2011-01-25 11:55:50 -05:00
WREG32 ( EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc - > crtc_offset , fb_swap ) ;
2010-01-12 17:54:34 -05:00
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 ) ;
2010-09-26 06:47:23 -05:00
WREG32 ( EVERGREEN_GRPH_X_END + radeon_crtc - > crtc_offset , target_fb - > width ) ;
WREG32 ( EVERGREEN_GRPH_Y_END + radeon_crtc - > crtc_offset , target_fb - > height ) ;
2010-01-12 17:54:34 -05:00
2010-09-26 06:47:23 -05:00
fb_pitch_pixels = target_fb - > pitch / ( target_fb - > bits_per_pixel / 8 ) ;
2010-01-12 17:54:34 -05:00
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 ) ;
2010-09-26 06:47:23 -05:00
if ( ! atomic & & fb & & fb ! = crtc - > fb ) {
radeon_fb = to_radeon_framebuffer ( fb ) ;
2010-01-12 17:54:34 -05: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 ) ;
}
/* Bytes per pixel may have changed */
radeon_bandwidth_update ( rdev ) ;
return 0 ;
}
2010-09-26 06:47:23 -05:00
static int avivo_crtc_do_set_base ( struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
int x , int y , int atomic )
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 ;
2010-09-26 06:47:23 -05:00
struct drm_framebuffer * target_fb ;
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 ;
2011-01-25 11:55:50 -05:00
u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE ;
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 */
2010-09-26 06:47:23 -05:00
if ( ! atomic & & ! crtc - > fb ) {
2010-08-02 10:42:55 +10:00
DRM_DEBUG_KMS ( " No FB bound \n " ) ;
2009-11-17 14:08:55 -08:00
return 0 ;
}
2009-06-05 14:42:42 +02:00
2010-09-26 06:47:23 -05:00
if ( atomic ) {
radeon_fb = to_radeon_framebuffer ( fb ) ;
target_fb = fb ;
}
else {
radeon_fb = to_radeon_framebuffer ( crtc - > fb ) ;
target_fb = crtc - > fb ;
}
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 ;
2010-09-26 06:47:23 -05:00
/* If atomic, assume fb object is pinned & idle & fenced and
* just update base pointers
*/
if ( atomic )
fb_location = radeon_bo_gpu_offset ( rbo ) ;
else {
r = radeon_bo_pin ( rbo , RADEON_GEM_DOMAIN_VRAM , & fb_location ) ;
if ( unlikely ( r ! = 0 ) ) {
radeon_bo_unreserve ( rbo ) ;
return - EINVAL ;
}
2009-06-05 14:42:42 +02:00
}
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
2010-09-26 06:47:23 -05:00
switch ( target_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 ;
2011-01-25 11:55:50 -05:00
# ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT ;
# endif
2009-06-05 14:42:42 +02:00
break ;
case 24 :
case 32 :
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 ;
2011-01-25 11:55:50 -05:00
# ifdef __BIG_ENDIAN
fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT ;
# endif
2009-06-05 14:42:42 +02:00
break ;
default :
DRM_ERROR ( " Unsupported screen depth %d \n " ,
2010-09-26 06:47:23 -05:00
target_fb - > bits_per_pixel ) ;
2009-06-05 14:42:42 +02:00
return - EINVAL ;
}
2010-05-20 12:04:59 -04:00
if ( rdev - > family > = CHIP_R600 ) {
if ( tiling_flags & RADEON_TILING_MACRO )
fb_format | = R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1 ;
else if ( tiling_flags & RADEON_TILING_MICRO )
fb_format | = R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1 ;
} else {
if ( tiling_flags & RADEON_TILING_MACRO )
fb_format | = AVIVO_D1GRPH_MACRO_ADDRESS_MODE ;
2009-12-08 15:45:13 +10:00
2010-05-20 12:04:59 -04:00
if ( tiling_flags & RADEON_TILING_MICRO )
fb_format | = AVIVO_D1GRPH_TILED ;
}
2009-06-24 09:48:08 +10:00
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 ) {
2010-09-01 17:20:42 -04:00
WREG32 ( R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH , upper_32_bits ( fb_location ) ) ;
WREG32 ( R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH , upper_32_bits ( fb_location ) ) ;
2009-10-22 16:12:34 -04:00
} else {
2010-09-01 17:20:42 -04:00
WREG32 ( R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH , upper_32_bits ( fb_location ) ) ;
WREG32 ( R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH , upper_32_bits ( fb_location ) ) ;
2009-10-22 16:12:34 -04:00
}
}
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 ) ;
2011-01-25 11:55:50 -05:00
if ( rdev - > family > = CHIP_R600 )
WREG32 ( R600_D1GRPH_SWAP_CONTROL + radeon_crtc - > crtc_offset , fb_swap ) ;
2009-06-05 14:42:42 +02:00
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 ) ;
2010-09-26 06:47:23 -05:00
WREG32 ( AVIVO_D1GRPH_X_END + radeon_crtc - > crtc_offset , target_fb - > width ) ;
WREG32 ( AVIVO_D1GRPH_Y_END + radeon_crtc - > crtc_offset , target_fb - > height ) ;
2009-06-05 14:42:42 +02:00
2010-09-26 06:47:23 -05:00
fb_pitch_pixels = target_fb - > pitch / ( target_fb - > bits_per_pixel / 8 ) ;
2009-06-05 14:42:42 +02:00
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 ) ;
2010-09-26 06:47:23 -05:00
if ( ! atomic & & fb & & fb ! = crtc - > fb ) {
radeon_fb = to_radeon_framebuffer ( 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 ) )
2010-09-26 06:47:23 -05:00
return evergreen_crtc_do_set_base ( crtc , old_fb , x , y , 0 ) ;
else if ( ASIC_IS_AVIVO ( rdev ) )
return avivo_crtc_do_set_base ( crtc , old_fb , x , y , 0 ) ;
else
return radeon_crtc_do_set_base ( crtc , old_fb , x , y , 0 ) ;
}
int atombios_crtc_set_base_atomic ( struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
2010-10-13 14:09:44 -05:00
int x , int y , enum mode_set_atomic state )
2010-09-26 06:47:23 -05:00
{
struct drm_device * dev = crtc - > dev ;
struct radeon_device * rdev = dev - > dev_private ;
if ( ASIC_IS_DCE4 ( rdev ) )
return evergreen_crtc_do_set_base ( crtc , fb , x , y , 1 ) ;
2010-01-12 17:54:34 -05:00
else if ( ASIC_IS_AVIVO ( rdev ) )
2010-09-26 06:47:23 -05:00
return avivo_crtc_do_set_base ( crtc , fb , x , y , 1 ) ;
2010-01-19 16:34:01 -05:00
else
2010-09-26 06:47:23 -05:00
return radeon_crtc_do_set_base ( crtc , fb , x , y , 1 ) ;
2010-01-19 16:34:01 -05:00
}
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 ;
2010-09-03 15:52:53 -04:00
struct drm_encoder * encoder ;
bool is_tvcv = false ;
2009-06-05 14:42:42 +02:00
2010-09-03 15:52:53 -04: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 | ATOM_DEVICE_CV_SUPPORT ) )
is_tvcv = true ;
}
}
2009-06-05 14:42:42 +02:00
2010-01-12 17:54:34 -05:00
/* always set DCPLL */
2010-10-04 17:13:01 -04:00
if ( ASIC_IS_DCE4 ( rdev ) ) {
struct radeon_atom_ss ss ;
bool ss_enabled = radeon_atombios_get_asic_ss_info ( rdev , & ss ,
ASIC_INTERNAL_SS_ON_DCPLL ,
rdev - > clock . default_dispclk ) ;
if ( ss_enabled )
atombios_crtc_program_ss ( crtc , ATOM_DISABLE , ATOM_DCPLL , & ss ) ;
2011-01-06 21:19:15 -05:00
/* XXX: DCE5, make sure voltage, dispclk is high enough */
atombios_crtc_set_dcpll ( crtc , rdev - > clock . default_dispclk ) ;
2010-10-04 17:13:01 -04:00
if ( ss_enabled )
atombios_crtc_program_ss ( crtc , ATOM_ENABLE , ATOM_DCPLL , & ss ) ;
}
2009-06-05 14:42:42 +02:00
atombios_crtc_set_pll ( crtc , adjusted_mode ) ;
2010-09-03 15:52:53 -04:00
if ( ASIC_IS_DCE4 ( rdev ) )
2010-01-12 17:54:34 -05:00
atombios_set_crtc_dtd_timing ( crtc , adjusted_mode ) ;
2010-09-03 15:52:53 -04:00
else if ( ASIC_IS_AVIVO ( rdev ) ) {
if ( is_tvcv )
atombios_crtc_set_timing ( crtc , adjusted_mode ) ;
else
atombios_set_crtc_dtd_timing ( crtc , adjusted_mode ) ;
} 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
}
2010-06-11 17:58:38 -04:00
static void atombios_crtc_disable ( struct drm_crtc * crtc )
{
struct radeon_crtc * radeon_crtc = to_radeon_crtc ( crtc ) ;
atombios_crtc_dpms ( crtc , DRM_MODE_DPMS_OFF ) ;
switch ( radeon_crtc - > pll_id ) {
case ATOM_PPLL1 :
case ATOM_PPLL2 :
/* disable the ppll */
atombios_crtc_program_pll ( crtc , radeon_crtc - > crtc_id , radeon_crtc - > pll_id ,
0 , 0 , ATOM_DISABLE , 0 , 0 , 0 , 0 ) ;
break ;
default :
break ;
}
radeon_crtc - > pll_id = - 1 ;
}
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 ,
2010-09-26 06:47:23 -05:00
. mode_set_base_atomic = atombios_crtc_set_base_atomic ,
2009-06-05 14:42:42 +02:00
. prepare = atombios_crtc_prepare ,
. commit = atombios_crtc_commit ,
2009-10-05 09:58:02 +10:00
. load_lut = radeon_crtc_load_lut ,
2010-06-11 17:58:38 -04:00
. disable = atombios_crtc_disable ,
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 ) ;
}