2011-11-03 18:22:26 +00:00
/*
* Copyright © 2006 - 2009 Intel Corporation
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Authors :
* Eric Anholt < eric @ anholt . net >
* Dave Airlie < airlied @ linux . ie >
* Jesse Barnes < jesse . barnes @ intel . com >
*/
# include <linux/i2c.h>
# include <drm/drmP.h>
2013-10-17 15:35:27 -07:00
# include <asm/intel-mid.h>
2011-11-03 18:22:26 +00:00
# include "intel_bios.h"
# include "psb_drv.h"
# include "psb_intel_drv.h"
# include "psb_intel_reg.h"
# include "power.h"
# include <linux/pm_runtime.h>
/* The max/min PWM frequency in BPCR[31:17] - */
/* The smallest number is 1 (not 0) that can fit in the
* 15 - bit field of the and then */
/* shifts to the left by one bit to get the actual 16-bit
* value that the 15 - bits correspond to . */
# define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
# define BRIGHTNESS_MAX_LEVEL 100
/**
* Sets the power state for the panel .
*/
static void oaktrail_lvds_set_power ( struct drm_device * dev ,
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder ,
2011-12-19 21:41:33 +00:00
bool on )
2011-11-03 18:22:26 +00:00
{
u32 pp_status ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
if ( ! gma_power_begin ( dev , true ) )
return ;
if ( on ) {
REG_WRITE ( PP_CONTROL , REG_READ ( PP_CONTROL ) |
POWER_TARGET_ON ) ;
do {
pp_status = REG_READ ( PP_STATUS ) ;
} while ( ( pp_status & ( PP_ON | PP_READY ) ) = = PP_READY ) ;
dev_priv - > is_lvds_on = true ;
if ( dev_priv - > ops - > lvds_bl_power )
dev_priv - > ops - > lvds_bl_power ( dev , true ) ;
} else {
if ( dev_priv - > ops - > lvds_bl_power )
dev_priv - > ops - > lvds_bl_power ( dev , false ) ;
REG_WRITE ( PP_CONTROL , REG_READ ( PP_CONTROL ) &
~ POWER_TARGET_ON ) ;
do {
pp_status = REG_READ ( PP_STATUS ) ;
} while ( pp_status & PP_ON ) ;
dev_priv - > is_lvds_on = false ;
pm_request_idle ( & dev - > pdev - > dev ) ;
}
gma_power_end ( dev ) ;
}
static void oaktrail_lvds_dpms ( struct drm_encoder * encoder , int mode )
{
struct drm_device * dev = encoder - > dev ;
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder = to_gma_encoder ( encoder ) ;
2011-11-03 18:22:26 +00:00
if ( mode = = DRM_MODE_DPMS_ON )
2013-07-22 17:45:26 +02:00
oaktrail_lvds_set_power ( dev , gma_encoder , true ) ;
2011-11-03 18:22:26 +00:00
else
2013-07-22 17:45:26 +02:00
oaktrail_lvds_set_power ( dev , gma_encoder , false ) ;
2011-11-03 18:22:26 +00:00
/* XXX: We never power down the LVDS pairs. */
}
static void oaktrail_lvds_mode_set ( struct drm_encoder * encoder ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct drm_device * dev = encoder - > dev ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
2011-12-19 21:41:33 +00:00
struct psb_intel_mode_device * mode_dev = & dev_priv - > mode_dev ;
struct drm_mode_config * mode_config = & dev - > mode_config ;
struct drm_connector * connector = NULL ;
struct drm_crtc * crtc = encoder - > crtc ;
2011-11-03 18:22:26 +00:00
u32 lvds_port ;
uint64_t v = DRM_MODE_SCALE_FULLSCREEN ;
if ( ! gma_power_begin ( dev , true ) )
return ;
/*
* The LVDS pin pair will already have been turned on in the
* psb_intel_crtc_mode_set since it has a large impact on the DPLL
* settings .
*/
lvds_port = ( REG_READ ( LVDS ) &
( ~ LVDS_PIPEB_SELECT ) ) |
LVDS_PORT_EN |
LVDS_BORDER_EN ;
/* If the firmware says dither on Moorestown, or the BIOS does
on Oaktrail then enable dithering */
if ( mode_dev - > panel_wants_dither | | dev_priv - > lvds_dither )
lvds_port | = MRST_PANEL_8TO6_DITHER_ENABLE ;
REG_WRITE ( LVDS , lvds_port ) ;
2011-12-19 21:41:33 +00:00
/* Find the connector we're trying to set up */
list_for_each_entry ( connector , & mode_config - > connector_list , head ) {
if ( ! connector - > encoder | | connector - > encoder - > crtc ! = crtc )
continue ;
}
if ( ! connector ) {
DRM_ERROR ( " Couldn't find connector when setting mode " ) ;
return ;
}
2012-10-11 20:38:23 -05:00
drm_object_property_get_value (
& connector - > base ,
2011-11-03 18:22:26 +00:00
dev - > mode_config . scaling_mode_property ,
& v ) ;
if ( v = = DRM_MODE_SCALE_NO_SCALE )
REG_WRITE ( PFIT_CONTROL , 0 ) ;
else if ( v = = DRM_MODE_SCALE_ASPECT ) {
if ( ( mode - > vdisplay ! = adjusted_mode - > crtc_vdisplay ) | |
( mode - > hdisplay ! = adjusted_mode - > crtc_hdisplay ) ) {
if ( ( adjusted_mode - > crtc_hdisplay * mode - > vdisplay ) = =
( mode - > hdisplay * adjusted_mode - > crtc_vdisplay ) )
REG_WRITE ( PFIT_CONTROL , PFIT_ENABLE ) ;
else if ( ( adjusted_mode - > crtc_hdisplay *
mode - > vdisplay ) > ( mode - > hdisplay *
adjusted_mode - > crtc_vdisplay ) )
REG_WRITE ( PFIT_CONTROL , PFIT_ENABLE |
PFIT_SCALING_MODE_PILLARBOX ) ;
else
REG_WRITE ( PFIT_CONTROL , PFIT_ENABLE |
PFIT_SCALING_MODE_LETTERBOX ) ;
} else
REG_WRITE ( PFIT_CONTROL , PFIT_ENABLE ) ;
} else /*(v == DRM_MODE_SCALE_FULLSCREEN)*/
REG_WRITE ( PFIT_CONTROL , PFIT_ENABLE ) ;
gma_power_end ( dev ) ;
}
static void oaktrail_lvds_prepare ( struct drm_encoder * encoder )
{
struct drm_device * dev = encoder - > dev ;
2011-12-19 21:41:33 +00:00
struct drm_psb_private * dev_priv = dev - > dev_private ;
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder = to_gma_encoder ( encoder ) ;
2011-12-19 21:41:33 +00:00
struct psb_intel_mode_device * mode_dev = & dev_priv - > mode_dev ;
2011-11-03 18:22:26 +00:00
if ( ! gma_power_begin ( dev , true ) )
return ;
mode_dev - > saveBLC_PWM_CTL = REG_READ ( BLC_PWM_CTL ) ;
mode_dev - > backlight_duty_cycle = ( mode_dev - > saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK ) ;
2013-07-22 17:45:26 +02:00
oaktrail_lvds_set_power ( dev , gma_encoder , false ) ;
2011-11-03 18:22:26 +00:00
gma_power_end ( dev ) ;
}
static u32 oaktrail_lvds_get_max_backlight ( struct drm_device * dev )
{
struct drm_psb_private * dev_priv = dev - > dev_private ;
u32 ret ;
if ( gma_power_begin ( dev , false ) ) {
ret = ( ( REG_READ ( BLC_PWM_CTL ) &
BACKLIGHT_MODULATION_FREQ_MASK ) > >
BACKLIGHT_MODULATION_FREQ_SHIFT ) * 2 ;
gma_power_end ( dev ) ;
} else
2012-03-08 16:00:31 +00:00
ret = ( ( dev_priv - > regs . saveBLC_PWM_CTL &
2011-11-03 18:22:26 +00:00
BACKLIGHT_MODULATION_FREQ_MASK ) > >
BACKLIGHT_MODULATION_FREQ_SHIFT ) * 2 ;
return ret ;
}
static void oaktrail_lvds_commit ( struct drm_encoder * encoder )
{
struct drm_device * dev = encoder - > dev ;
2011-12-19 21:41:33 +00:00
struct drm_psb_private * dev_priv = dev - > dev_private ;
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder = to_gma_encoder ( encoder ) ;
2011-12-19 21:41:33 +00:00
struct psb_intel_mode_device * mode_dev = & dev_priv - > mode_dev ;
2011-11-03 18:22:26 +00:00
if ( mode_dev - > backlight_duty_cycle = = 0 )
mode_dev - > backlight_duty_cycle =
oaktrail_lvds_get_max_backlight ( dev ) ;
2013-07-22 17:45:26 +02:00
oaktrail_lvds_set_power ( dev , gma_encoder , true ) ;
2011-11-03 18:22:26 +00:00
}
static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = {
. dpms = oaktrail_lvds_dpms ,
. mode_fixup = psb_intel_lvds_mode_fixup ,
. prepare = oaktrail_lvds_prepare ,
. mode_set = oaktrail_lvds_mode_set ,
. commit = oaktrail_lvds_commit ,
} ;
/* Returns the panel fixed mode from configuration. */
2011-11-29 22:27:57 +00:00
static void oaktrail_lvds_get_configuration_mode ( struct drm_device * dev ,
struct psb_intel_mode_device * mode_dev )
2011-11-03 18:22:26 +00:00
{
struct drm_display_mode * mode = NULL ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
struct oaktrail_timing_info * ti = & dev_priv - > gct_data . DTD ;
2011-11-29 22:27:57 +00:00
mode_dev - > panel_fixed_mode = NULL ;
/* Use the firmware provided data on Moorestown */
2012-05-03 16:27:21 +01:00
if ( dev_priv - > has_gct ) {
2011-11-03 18:22:26 +00:00
mode = kzalloc ( sizeof ( * mode ) , GFP_KERNEL ) ;
if ( ! mode )
2011-11-29 22:27:57 +00:00
return ;
2011-11-03 18:22:26 +00:00
mode - > hdisplay = ( ti - > hactive_hi < < 8 ) | ti - > hactive_lo ;
mode - > vdisplay = ( ti - > vactive_hi < < 8 ) | ti - > vactive_lo ;
mode - > hsync_start = mode - > hdisplay + \
( ( ti - > hsync_offset_hi < < 8 ) | \
ti - > hsync_offset_lo ) ;
mode - > hsync_end = mode - > hsync_start + \
( ( ti - > hsync_pulse_width_hi < < 8 ) | \
ti - > hsync_pulse_width_lo ) ;
mode - > htotal = mode - > hdisplay + ( ( ti - > hblank_hi < < 8 ) | \
ti - > hblank_lo ) ;
mode - > vsync_start = \
mode - > vdisplay + ( ( ti - > vsync_offset_hi < < 4 ) | \
ti - > vsync_offset_lo ) ;
mode - > vsync_end = \
mode - > vsync_start + ( ( ti - > vsync_pulse_width_hi < < 4 ) | \
ti - > vsync_pulse_width_lo ) ;
mode - > vtotal = mode - > vdisplay + \
( ( ti - > vblank_hi < < 8 ) | ti - > vblank_lo ) ;
mode - > clock = ti - > pixel_clock * 10 ;
#if 0
2017-02-28 04:55:54 -08:00
pr_info ( " hdisplay is %d \n " , mode - > hdisplay ) ;
pr_info ( " vdisplay is %d \n " , mode - > vdisplay ) ;
pr_info ( " HSS is %d \n " , mode - > hsync_start ) ;
pr_info ( " HSE is %d \n " , mode - > hsync_end ) ;
pr_info ( " htotal is %d \n " , mode - > htotal ) ;
pr_info ( " VSS is %d \n " , mode - > vsync_start ) ;
pr_info ( " VSE is %d \n " , mode - > vsync_end ) ;
pr_info ( " vtotal is %d \n " , mode - > vtotal ) ;
pr_info ( " clock is %d \n " , mode - > clock ) ;
2011-11-03 18:22:26 +00:00
# endif
2011-11-29 22:27:57 +00:00
mode_dev - > panel_fixed_mode = mode ;
}
2011-11-03 18:22:26 +00:00
2011-11-29 22:27:57 +00:00
/* Use the BIOS VBT mode if available */
if ( mode_dev - > panel_fixed_mode = = NULL & & mode_dev - > vbt_mode )
mode_dev - > panel_fixed_mode = drm_mode_duplicate ( dev ,
mode_dev - > vbt_mode ) ;
/* Then try the LVDS VBT mode */
if ( mode_dev - > panel_fixed_mode = = NULL )
if ( dev_priv - > lfp_lvds_vbt_mode )
mode_dev - > panel_fixed_mode =
drm_mode_duplicate ( dev ,
dev_priv - > lfp_lvds_vbt_mode ) ;
2013-11-08 16:00:33 +01:00
/* If we still got no mode then bail */
2011-11-29 22:27:57 +00:00
if ( mode_dev - > panel_fixed_mode = = NULL )
2013-11-08 16:00:33 +01:00
return ;
2011-11-29 22:27:57 +00:00
drm_mode_set_name ( mode_dev - > panel_fixed_mode ) ;
drm_mode_set_crtcinfo ( mode_dev - > panel_fixed_mode , 0 ) ;
2011-11-03 18:22:26 +00:00
}
/**
* oaktrail_lvds_init - setup LVDS connectors on this device
* @ dev : drm device
*
* Create the connector , register the LVDS DDC bus , and try to figure out what
* modes we can display on the LVDS panel ( if present ) .
*/
void oaktrail_lvds_init ( struct drm_device * dev ,
struct psb_intel_mode_device * mode_dev )
{
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder ;
2013-07-22 17:05:25 +02:00
struct gma_connector * gma_connector ;
2011-11-03 18:22:26 +00:00
struct drm_connector * connector ;
struct drm_encoder * encoder ;
2011-12-20 15:58:29 +00:00
struct drm_psb_private * dev_priv = dev - > dev_private ;
2011-11-03 18:22:26 +00:00
struct edid * edid ;
struct i2c_adapter * i2c_adap ;
struct drm_display_mode * scan ; /* *modes, *bios_mode; */
2013-07-22 17:45:26 +02:00
gma_encoder = kzalloc ( sizeof ( struct gma_encoder ) , GFP_KERNEL ) ;
if ( ! gma_encoder )
2011-11-03 18:22:26 +00:00
return ;
2013-07-22 17:05:25 +02:00
gma_connector = kzalloc ( sizeof ( struct gma_connector ) , GFP_KERNEL ) ;
if ( ! gma_connector )
2011-12-19 21:41:33 +00:00
goto failed_connector ;
2013-07-22 17:05:25 +02:00
connector = & gma_connector - > base ;
2013-07-22 17:45:26 +02:00
encoder = & gma_encoder - > base ;
2011-11-03 18:22:26 +00:00
dev_priv - > is_lvds_on = true ;
2011-12-19 21:41:33 +00:00
drm_connector_init ( dev , connector ,
2011-11-03 18:22:26 +00:00
& psb_intel_lvds_connector_funcs ,
DRM_MODE_CONNECTOR_LVDS ) ;
2011-12-19 21:41:33 +00:00
drm_encoder_init ( dev , encoder , & psb_intel_lvds_enc_funcs ,
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
DRM_MODE_ENCODER_LVDS , NULL ) ;
2011-11-03 18:22:26 +00:00
2013-07-22 17:45:26 +02:00
gma_connector_attach_encoder ( gma_connector , gma_encoder ) ;
gma_encoder - > type = INTEL_OUTPUT_LVDS ;
2011-11-03 18:22:26 +00:00
drm_encoder_helper_add ( encoder , & oaktrail_lvds_helper_funcs ) ;
drm_connector_helper_add ( connector ,
& psb_intel_lvds_connector_helper_funcs ) ;
connector - > display_info . subpixel_order = SubPixelHorizontalRGB ;
connector - > interlace_allowed = false ;
connector - > doublescan_allowed = false ;
2012-10-11 20:38:23 -05:00
drm_object_attach_property ( & connector - > base ,
2011-11-03 18:22:26 +00:00
dev - > mode_config . scaling_mode_property ,
DRM_MODE_SCALE_FULLSCREEN ) ;
2012-10-11 20:38:23 -05:00
drm_object_attach_property ( & connector - > base ,
2011-11-03 18:22:26 +00:00
dev_priv - > backlight_property ,
BRIGHTNESS_MAX_LEVEL ) ;
mode_dev - > panel_wants_dither = false ;
2012-05-03 16:27:21 +01:00
if ( dev_priv - > has_gct )
2011-11-03 18:22:26 +00:00
mode_dev - > panel_wants_dither = ( dev_priv - > gct_data .
Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE ) ;
2011-12-20 15:58:44 +00:00
if ( dev_priv - > lvds_dither )
mode_dev - > panel_wants_dither = 1 ;
2011-11-03 18:22:26 +00:00
/*
* LVDS discovery :
* 1 ) check for EDID on DDC
* 2 ) check for VBT data
* 3 ) check to see if LVDS is already on
* if none of the above , no panel
* 4 ) make sure lid is open
* if closed , act like it ' s not there for now
*/
2014-09-26 10:40:29 +02:00
edid = NULL ;
2014-03-21 23:22:36 +01:00
mutex_lock ( & dev - > mode_config . mutex ) ;
2011-11-03 18:22:26 +00:00
i2c_adap = i2c_get_adapter ( dev_priv - > ops - > i2c_bus ) ;
2014-09-26 10:40:29 +02:00
if ( i2c_adap )
edid = drm_get_edid ( connector , i2c_adap ) ;
if ( edid = = NULL & & dev_priv - > lpc_gpio_base ) {
oaktrail_lvds_i2c_init ( encoder ) ;
if ( gma_encoder - > ddc_bus ! = NULL ) {
i2c_adap = & gma_encoder - > ddc_bus - > adapter ;
edid = drm_get_edid ( connector , i2c_adap ) ;
}
}
2011-11-03 18:22:26 +00:00
/*
* Attempt to get the fixed panel mode from DDC . Assume that the
* preferred mode is the right one .
*/
2014-09-26 10:40:29 +02:00
if ( edid ) {
2018-07-09 10:40:06 +02:00
drm_connector_update_edid_property ( connector , edid ) ;
2014-09-26 10:40:29 +02:00
drm_add_edid_modes ( connector , edid ) ;
kfree ( edid ) ;
2011-11-03 18:22:26 +00:00
list_for_each_entry ( scan , & connector - > probed_modes , head ) {
if ( scan - > type & DRM_MODE_TYPE_PREFERRED ) {
mode_dev - > panel_fixed_mode =
drm_mode_duplicate ( dev , scan ) ;
goto out ; /* FIXME: check for quirks */
}
}
2014-09-26 10:40:29 +02:00
} else
dev_err ( dev - > dev , " No ddc adapter available! \n " ) ;
2011-11-03 18:22:26 +00:00
/*
* If we didn ' t get EDID , try geting panel timing
* from configuration data
*/
2011-11-29 22:27:57 +00:00
oaktrail_lvds_get_configuration_mode ( dev , mode_dev ) ;
2011-11-03 18:22:26 +00:00
if ( mode_dev - > panel_fixed_mode ) {
mode_dev - > panel_fixed_mode - > type | = DRM_MODE_TYPE_PREFERRED ;
goto out ; /* FIXME: check for quirks */
}
/* If we still don't have a mode after all that, give up. */
if ( ! mode_dev - > panel_fixed_mode ) {
dev_err ( dev - > dev , " Found no modes on the lvds, ignoring the LVDS \n " ) ;
goto failed_find ;
}
out :
2014-03-21 23:22:36 +01:00
mutex_unlock ( & dev - > mode_config . mutex ) ;
2014-05-29 16:57:41 +01:00
drm_connector_register ( connector ) ;
2011-11-03 18:22:26 +00:00
return ;
failed_find :
2014-03-21 23:22:36 +01:00
mutex_unlock ( & dev - > mode_config . mutex ) ;
2011-11-03 18:22:26 +00:00
dev_dbg ( dev - > dev , " No LVDS modes found, disabling. \n " ) ;
2014-09-26 10:40:29 +02:00
if ( gma_encoder - > ddc_bus ) {
2013-07-22 17:45:26 +02:00
psb_intel_i2c_destroy ( gma_encoder - > ddc_bus ) ;
2014-09-26 10:40:29 +02:00
gma_encoder - > ddc_bus = NULL ;
}
2011-11-03 18:22:26 +00:00
/* failed_ddc: */
drm_encoder_cleanup ( encoder ) ;
drm_connector_cleanup ( connector ) ;
2013-07-22 17:05:25 +02:00
kfree ( gma_connector ) ;
2011-12-19 21:41:33 +00:00
failed_connector :
2013-07-22 17:45:26 +02:00
kfree ( gma_encoder ) ;
2011-11-03 18:22:26 +00:00
}