2011-11-03 18:22:15 +00:00
/*
* Copyright  © 2006 - 2011 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 >
*/
# include <linux/i2c.h>
# include <drm/drmP.h>
2014-10-29 10:03:57 +01:00
# include <drm/drm_plane_helper.h>
2011-11-03 18:22:15 +00:00
# include "framebuffer.h"
# include "psb_drv.h"
# include "psb_intel_drv.h"
# include "psb_intel_reg.h"
2013-07-02 17:07:59 +02:00
# include "gma_display.h"
2011-11-03 18:22:15 +00:00
# include "power.h"
2013-03-13 23:24:08 +01:00
# define INTEL_LIMIT_I9XX_SDVO_DAC 0
# define INTEL_LIMIT_I9XX_LVDS 1
2011-11-03 18:22:15 +00:00
2013-07-02 17:07:59 +02:00
static const struct gma_limit_t psb_intel_limits [ ] = {
2011-11-03 18:22:15 +00:00
{ /* INTEL_LIMIT_I9XX_SDVO_DAC */
2013-03-14 00:14:06 +01:00
. dot = { . min = 20000 , . max = 400000 } ,
. vco = { . min = 1400000 , . max = 2800000 } ,
. n = { . min = 1 , . max = 6 } ,
. m = { . min = 70 , . max = 120 } ,
. m1 = { . min = 8 , . max = 18 } ,
. m2 = { . min = 3 , . max = 7 } ,
. p = { . min = 5 , . max = 80 } ,
. p1 = { . min = 1 , . max = 8 } ,
2013-07-02 17:07:59 +02:00
. p2 = { . dot_limit = 200000 , . p2_slow = 10 , . p2_fast = 5 } ,
. find_pll = gma_find_best_pll ,
2011-11-03 18:22:15 +00:00
} ,
{ /* INTEL_LIMIT_I9XX_LVDS */
2013-03-14 00:14:06 +01:00
. dot = { . min = 20000 , . max = 400000 } ,
. vco = { . min = 1400000 , . max = 2800000 } ,
. n = { . min = 1 , . max = 6 } ,
. m = { . min = 70 , . max = 120 } ,
. m1 = { . min = 8 , . max = 18 } ,
. m2 = { . min = 3 , . max = 7 } ,
. p = { . min = 7 , . max = 98 } ,
. p1 = { . min = 1 , . max = 8 } ,
2011-11-03 18:22:15 +00:00
/* The single-channel range is 25-112Mhz, and dual-channel
* is 80 - 224 Mhz . Prefer single channel as much as possible .
*/
2013-07-02 17:07:59 +02:00
. p2 = { . dot_limit = 112000 , . p2_slow = 14 , . p2_fast = 7 } ,
. find_pll = gma_find_best_pll ,
2011-11-03 18:22:15 +00:00
} ,
} ;
2013-07-02 17:07:59 +02:00
static const struct gma_limit_t * psb_intel_limit ( struct drm_crtc * crtc ,
int refclk )
2011-11-03 18:22:15 +00:00
{
2013-07-02 17:07:59 +02:00
const struct gma_limit_t * limit ;
2011-11-03 18:22:15 +00:00
2013-07-02 17:07:59 +02:00
if ( gma_pipe_has_type ( crtc , INTEL_OUTPUT_LVDS ) )
2011-11-03 18:22:15 +00:00
limit = & psb_intel_limits [ INTEL_LIMIT_I9XX_LVDS ] ;
else
limit = & psb_intel_limits [ INTEL_LIMIT_I9XX_SDVO_DAC ] ;
return limit ;
}
2013-07-02 17:07:59 +02:00
static void psb_intel_clock ( int refclk , struct gma_clock_t * clock )
2011-11-03 18:22:15 +00:00
{
clock - > m = 5 * ( clock - > m1 + 2 ) + ( clock - > m2 + 2 ) ;
clock - > p = clock - > p1 * clock - > p2 ;
clock - > vco = refclk * clock - > m / ( clock - > n + 2 ) ;
clock - > dot = clock - > vco / clock - > p ;
}
/**
* Return the pipe currently connected to the panel fitter ,
* or - 1 if the panel fitter is not present or not in use
*/
static int psb_intel_panel_fitter_pipe ( struct drm_device * dev )
{
u32 pfit_control ;
pfit_control = REG_READ ( PFIT_CONTROL ) ;
/* See if the panel fitter is in use */
if ( ( pfit_control & PFIT_ENABLE ) = = 0 )
return - 1 ;
/* Must be on PIPE 1 for PSB */
return 1 ;
}
static int psb_intel_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 drm_device * dev = crtc - > dev ;
2012-05-11 11:31:22 +01:00
struct drm_psb_private * dev_priv = dev - > dev_private ;
2013-07-22 01:31:23 +02:00
struct gma_crtc * gma_crtc = to_gma_crtc ( crtc ) ;
2015-03-11 11:51:01 +02:00
const struct drm_crtc_helper_funcs * crtc_funcs = crtc - > helper_private ;
2013-07-22 01:31:23 +02:00
int pipe = gma_crtc - > pipe ;
2012-05-11 11:31:22 +01:00
const struct psb_offset * map = & dev_priv - > regmap [ pipe ] ;
2011-11-03 18:22:15 +00:00
int refclk ;
2013-07-02 17:07:59 +02:00
struct gma_clock_t clock ;
2011-11-03 18:22:15 +00:00
u32 dpll = 0 , fp = 0 , dspcntr , pipeconf ;
2012-03-08 16:15:20 +00:00
bool ok , is_sdvo = false ;
bool is_lvds = false , is_tv = false ;
2011-11-03 18:22:15 +00:00
struct drm_mode_config * mode_config = & dev - > mode_config ;
struct drm_connector * connector ;
2013-07-02 17:07:59 +02:00
const struct gma_limit_t * limit ;
2011-11-03 18:22:15 +00:00
/* No scan out no play */
2014-04-01 15:22:40 -07:00
if ( crtc - > primary - > fb = = NULL ) {
2011-11-03 18:22:15 +00:00
crtc_funcs - > mode_set_base ( crtc , x , y , old_fb ) ;
return 0 ;
}
list_for_each_entry ( connector , & mode_config - > connector_list , head ) {
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder = gma_attached_encoder ( connector ) ;
2011-11-03 18:22:15 +00:00
if ( ! connector - > encoder
| | connector - > encoder - > crtc ! = crtc )
continue ;
2013-07-22 17:45:26 +02:00
switch ( gma_encoder - > type ) {
2011-11-03 18:22:15 +00:00
case INTEL_OUTPUT_LVDS :
is_lvds = true ;
break ;
case INTEL_OUTPUT_SDVO :
is_sdvo = true ;
break ;
case INTEL_OUTPUT_TVOUT :
is_tv = true ;
break ;
}
}
refclk = 96000 ;
2013-07-22 01:31:23 +02:00
limit = gma_crtc - > clock_funcs - > limit ( crtc , refclk ) ;
2013-07-02 17:07:59 +02:00
ok = limit - > find_pll ( limit , crtc , adjusted_mode - > clock , refclk ,
2011-11-03 18:22:15 +00:00
& clock ) ;
if ( ! ok ) {
2013-07-02 17:07:59 +02:00
DRM_ERROR ( " Couldn't find PLL settings for mode! target: %d, actual: %d " ,
adjusted_mode - > clock , clock . dot ) ;
2011-11-03 18:22:15 +00:00
return 0 ;
}
fp = clock . n < < 16 | clock . m1 < < 8 | clock . m2 ;
dpll = DPLL_VGA_MODE_DIS ;
if ( is_lvds ) {
dpll | = DPLLB_MODE_LVDS ;
dpll | = DPLL_DVO_HIGH_SPEED ;
} else
dpll | = DPLLB_MODE_DAC_SERIAL ;
if ( is_sdvo ) {
int sdvo_pixel_multiply =
adjusted_mode - > clock / mode - > clock ;
dpll | = DPLL_DVO_HIGH_SPEED ;
dpll | =
( sdvo_pixel_multiply - 1 ) < < SDVO_MULTIPLIER_SHIFT_HIRES ;
}
/* compute bitmask from p1 value */
dpll | = ( 1 < < ( clock . p1 - 1 ) ) < < 16 ;
switch ( clock . p2 ) {
case 5 :
dpll | = DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ;
break ;
case 7 :
dpll | = DPLLB_LVDS_P2_CLOCK_DIV_7 ;
break ;
case 10 :
dpll | = DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 ;
break ;
case 14 :
dpll | = DPLLB_LVDS_P2_CLOCK_DIV_14 ;
break ;
}
if ( is_tv ) {
/* XXX: just matching BIOS for now */
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll | = 3 ;
}
dpll | = PLL_REF_INPUT_DREFCLK ;
/* setup pipeconf */
2012-05-11 11:31:22 +01:00
pipeconf = REG_READ ( map - > conf ) ;
2011-11-03 18:22:15 +00:00
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE ;
if ( pipe = = 0 )
dspcntr | = DISPPLANE_SEL_PIPE_A ;
else
dspcntr | = DISPPLANE_SEL_PIPE_B ;
dspcntr | = DISPLAY_PLANE_ENABLE ;
pipeconf | = PIPEACONF_ENABLE ;
dpll | = DPLL_VCO_ENABLE ;
/* Disable the panel fitter if it was on our pipe */
if ( psb_intel_panel_fitter_pipe ( dev ) = = pipe )
REG_WRITE ( PFIT_CONTROL , 0 ) ;
drm_mode_debug_printmodeline ( mode ) ;
if ( dpll & DPLL_VCO_ENABLE ) {
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > fp0 , fp ) ;
REG_WRITE ( map - > dpll , dpll & ~ DPLL_VCO_ENABLE ) ;
REG_READ ( map - > dpll ) ;
2011-11-03 18:22:15 +00:00
udelay ( 150 ) ;
}
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn ' t turn
* things on .
*/
if ( is_lvds ) {
u32 lvds = REG_READ ( LVDS ) ;
lvds & = ~ LVDS_PIPEB_SELECT ;
if ( pipe = = 1 )
lvds | = LVDS_PIPEB_SELECT ;
lvds | = LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP ;
/* Set the B0-B3 data pairs corresponding to
* whether we ' re going to
* set the DPLLs for dual - channel mode or not .
*/
lvds & = ~ ( LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP ) ;
if ( clock . p2 = = 7 )
lvds | = LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP ;
/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
* appropriately here , but we need to look more
* thoroughly into how panels behave in the two modes .
*/
REG_WRITE ( LVDS , lvds ) ;
REG_READ ( LVDS ) ;
}
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > fp0 , fp ) ;
REG_WRITE ( map - > dpll , dpll ) ;
REG_READ ( map - > dpll ) ;
2011-11-03 18:22:15 +00:00
/* Wait for the clocks to stabilize. */
udelay ( 150 ) ;
/* write it again -- the BIOS does, after all */
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > dpll , dpll ) ;
2011-11-03 18:22:15 +00:00
2012-05-11 11:31:22 +01:00
REG_READ ( map - > dpll ) ;
2011-11-03 18:22:15 +00:00
/* Wait for the clocks to stabilize. */
udelay ( 150 ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > htotal , ( adjusted_mode - > crtc_hdisplay - 1 ) |
2011-11-03 18:22:15 +00:00
( ( adjusted_mode - > crtc_htotal - 1 ) < < 16 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > hblank , ( adjusted_mode - > crtc_hblank_start - 1 ) |
2011-11-03 18:22:15 +00:00
( ( adjusted_mode - > crtc_hblank_end - 1 ) < < 16 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > hsync , ( adjusted_mode - > crtc_hsync_start - 1 ) |
2011-11-03 18:22:15 +00:00
( ( adjusted_mode - > crtc_hsync_end - 1 ) < < 16 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > vtotal , ( adjusted_mode - > crtc_vdisplay - 1 ) |
2011-11-03 18:22:15 +00:00
( ( adjusted_mode - > crtc_vtotal - 1 ) < < 16 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > vblank , ( adjusted_mode - > crtc_vblank_start - 1 ) |
2011-11-03 18:22:15 +00:00
( ( adjusted_mode - > crtc_vblank_end - 1 ) < < 16 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > vsync , ( adjusted_mode - > crtc_vsync_start - 1 ) |
2011-11-03 18:22:15 +00:00
( ( adjusted_mode - > crtc_vsync_end - 1 ) < < 16 ) ) ;
/* pipesrc and dspsize control the size that is scaled from,
* which should always be the user ' s requested size .
*/
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > size ,
2011-11-03 18:22:15 +00:00
( ( mode - > vdisplay - 1 ) < < 16 ) | ( mode - > hdisplay - 1 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > pos , 0 ) ;
REG_WRITE ( map - > src ,
2011-11-03 18:22:15 +00:00
( ( mode - > hdisplay - 1 ) < < 16 ) | ( mode - > vdisplay - 1 ) ) ;
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > conf , pipeconf ) ;
REG_READ ( map - > conf ) ;
2011-11-03 18:22:15 +00:00
2013-07-10 01:20:19 +02:00
gma_wait_for_vblank ( dev ) ;
2011-11-03 18:22:15 +00:00
2012-05-11 11:31:22 +01:00
REG_WRITE ( map - > cntr , dspcntr ) ;
2011-11-03 18:22:15 +00:00
/* Flush the plane changes */
crtc_funcs - > mode_set_base ( crtc , x , y , old_fb ) ;
2013-07-10 01:20:19 +02:00
gma_wait_for_vblank ( dev ) ;
2011-11-03 18:22:15 +00:00
return 0 ;
}
/* Returns the clock of the currently programmed mode of the given pipe. */
static int psb_intel_crtc_clock_get ( struct drm_device * dev ,
struct drm_crtc * crtc )
{
2013-07-22 01:31:23 +02:00
struct gma_crtc * gma_crtc = to_gma_crtc ( crtc ) ;
2012-05-11 11:31:22 +01:00
struct drm_psb_private * dev_priv = dev - > dev_private ;
2013-07-22 01:31:23 +02:00
int pipe = gma_crtc - > pipe ;
2012-05-11 11:31:22 +01:00
const struct psb_offset * map = & dev_priv - > regmap [ pipe ] ;
2011-11-03 18:22:15 +00:00
u32 dpll ;
u32 fp ;
2013-07-02 17:07:59 +02:00
struct gma_clock_t clock ;
2011-11-03 18:22:15 +00:00
bool is_lvds ;
2012-05-11 11:30:16 +01:00
struct psb_pipe * p = & dev_priv - > regs . pipe [ pipe ] ;
2011-11-03 18:22:15 +00:00
if ( gma_power_begin ( dev , false ) ) {
2012-05-11 11:31:22 +01:00
dpll = REG_READ ( map - > dpll ) ;
2011-11-03 18:22:15 +00:00
if ( ( dpll & DISPLAY_RATE_SELECT_FPA1 ) = = 0 )
2012-05-11 11:31:22 +01:00
fp = REG_READ ( map - > fp0 ) ;
2011-11-03 18:22:15 +00:00
else
2012-05-11 11:31:22 +01:00
fp = REG_READ ( map - > fp1 ) ;
2011-11-03 18:22:15 +00:00
is_lvds = ( pipe = = 1 ) & & ( REG_READ ( LVDS ) & LVDS_PORT_EN ) ;
gma_power_end ( dev ) ;
} else {
2012-05-11 11:30:16 +01:00
dpll = p - > dpll ;
2011-11-03 18:22:15 +00:00
if ( ( dpll & DISPLAY_RATE_SELECT_FPA1 ) = = 0 )
2012-05-11 11:30:16 +01:00
fp = p - > fp0 ;
2011-11-03 18:22:15 +00:00
else
2012-05-11 11:30:16 +01:00
fp = p - > fp1 ;
2011-11-03 18:22:15 +00:00
2012-03-08 16:02:05 +00:00
is_lvds = ( pipe = = 1 ) & & ( dev_priv - > regs . psb . saveLVDS &
2012-03-08 16:00:31 +00:00
LVDS_PORT_EN ) ;
2011-11-03 18:22:15 +00:00
}
clock . m1 = ( fp & FP_M1_DIV_MASK ) > > FP_M1_DIV_SHIFT ;
clock . m2 = ( fp & FP_M2_DIV_MASK ) > > FP_M2_DIV_SHIFT ;
clock . n = ( fp & FP_N_DIV_MASK ) > > FP_N_DIV_SHIFT ;
if ( is_lvds ) {
clock . p1 =
ffs ( ( dpll &
DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS ) > >
DPLL_FPA01_P1_POST_DIV_SHIFT ) ;
clock . p2 = 14 ;
if ( ( dpll & PLL_REF_INPUT_MASK ) = =
PLLB_REF_INPUT_SPREADSPECTRUMIN ) {
/* XXX: might not be 66MHz */
2013-03-13 23:32:36 +01:00
psb_intel_clock ( 66000 , & clock ) ;
2011-11-03 18:22:15 +00:00
} else
2013-03-13 23:32:36 +01:00
psb_intel_clock ( 48000 , & clock ) ;
2011-11-03 18:22:15 +00:00
} else {
if ( dpll & PLL_P1_DIVIDE_BY_TWO )
clock . p1 = 2 ;
else {
clock . p1 =
( ( dpll &
DPLL_FPA01_P1_POST_DIV_MASK_I830 ) > >
DPLL_FPA01_P1_POST_DIV_SHIFT ) + 2 ;
}
if ( dpll & PLL_P2_DIVIDE_BY_4 )
clock . p2 = 4 ;
else
clock . p2 = 2 ;
2013-03-13 23:32:36 +01:00
psb_intel_clock ( 48000 , & clock ) ;
2011-11-03 18:22:15 +00:00
}
/* XXX: It would be nice to validate the clocks, but we can't reuse
* i830PllIsValid ( ) because it relies on the xf86_config connector
* configuration being accurate , which it isn ' t necessarily .
*/
return clock . dot ;
}
/** Returns the currently programmed mode of the given pipe. */
struct drm_display_mode * psb_intel_crtc_mode_get ( struct drm_device * dev ,
struct drm_crtc * crtc )
{
2013-07-22 01:31:23 +02:00
struct gma_crtc * gma_crtc = to_gma_crtc ( crtc ) ;
int pipe = gma_crtc - > pipe ;
2011-11-03 18:22:15 +00:00
struct drm_display_mode * mode ;
int htot ;
int hsync ;
int vtot ;
int vsync ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
2012-05-11 11:30:16 +01:00
struct psb_pipe * p = & dev_priv - > regs . pipe [ pipe ] ;
2012-05-11 11:31:22 +01:00
const struct psb_offset * map = & dev_priv - > regmap [ pipe ] ;
2011-11-03 18:22:15 +00:00
if ( gma_power_begin ( dev , false ) ) {
2012-05-11 11:31:22 +01:00
htot = REG_READ ( map - > htotal ) ;
hsync = REG_READ ( map - > hsync ) ;
vtot = REG_READ ( map - > vtotal ) ;
vsync = REG_READ ( map - > vsync ) ;
2011-11-03 18:22:15 +00:00
gma_power_end ( dev ) ;
} else {
2012-05-11 11:30:16 +01:00
htot = p - > htotal ;
hsync = p - > hsync ;
vtot = p - > vtotal ;
vsync = p - > vsync ;
2011-11-03 18:22:15 +00:00
}
mode = kzalloc ( sizeof ( * mode ) , GFP_KERNEL ) ;
if ( ! mode )
return NULL ;
mode - > clock = psb_intel_crtc_clock_get ( dev , crtc ) ;
mode - > hdisplay = ( htot & 0xffff ) + 1 ;
mode - > htotal = ( ( htot & 0xffff0000 ) > > 16 ) + 1 ;
mode - > hsync_start = ( hsync & 0xffff ) + 1 ;
mode - > hsync_end = ( ( hsync & 0xffff0000 ) > > 16 ) + 1 ;
mode - > vdisplay = ( vtot & 0xffff ) + 1 ;
mode - > vtotal = ( ( vtot & 0xffff0000 ) > > 16 ) + 1 ;
mode - > vsync_start = ( vsync & 0xffff ) + 1 ;
mode - > vsync_end = ( ( vsync & 0xffff0000 ) > > 16 ) + 1 ;
drm_mode_set_name ( mode ) ;
drm_mode_set_crtcinfo ( mode , 0 ) ;
return mode ;
}
const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
2013-07-10 18:44:25 +02:00
. dpms = gma_crtc_dpms ,
2011-11-03 18:22:15 +00:00
. mode_set = psb_intel_crtc_mode_set ,
2013-07-10 18:37:03 +02:00
. mode_set_base = gma_pipe_set_base ,
2013-07-10 17:40:54 +02:00
. prepare = gma_crtc_prepare ,
. commit = gma_crtc_commit ,
. disable = gma_crtc_disable ,
2011-11-03 18:22:15 +00:00
} ;
const struct drm_crtc_funcs psb_intel_crtc_funcs = {
2013-07-10 23:48:13 +02:00
. cursor_set = gma_crtc_cursor_set ,
. cursor_move = gma_crtc_cursor_move ,
2013-07-10 18:39:58 +02:00
. gamma_set = gma_crtc_gamma_set ,
2013-07-12 15:41:36 +02:00
. set_config = gma_crtc_set_config ,
2013-07-10 23:24:22 +02:00
. destroy = gma_crtc_destroy ,
2011-11-03 18:22:15 +00:00
} ;
2013-07-02 17:07:59 +02:00
const struct gma_clock_funcs psb_clock_funcs = {
. clock = psb_intel_clock ,
. limit = psb_intel_limit ,
. pll_is_valid = gma_pll_is_valid ,
} ;
2011-11-03 18:22:15 +00:00
/*
* Set the default value of cursor control and base register
* to zero . This is a workaround for h / w defect on Oaktrail
*/
2012-05-21 15:27:30 +01:00
static void psb_intel_cursor_init ( struct drm_device * dev ,
2013-07-22 01:31:23 +02:00
struct gma_crtc * gma_crtc )
2011-11-03 18:22:15 +00:00
{
2012-05-21 15:27:30 +01:00
struct drm_psb_private * dev_priv = dev - > dev_private ;
2011-11-03 18:22:15 +00:00
u32 control [ 3 ] = { CURACNTR , CURBCNTR , CURCCNTR } ;
u32 base [ 3 ] = { CURABASE , CURBBASE , CURCBASE } ;
2012-05-21 15:27:30 +01:00
struct gtt_range * cursor_gt ;
if ( dev_priv - > ops - > cursor_needs_phys ) {
/* Allocate 4 pages of stolen mem for a hardware cursor. That
* is enough for the 64 x 64 ARGB cursors we support .
*/
2014-01-06 02:39:10 +01:00
cursor_gt = psb_gtt_alloc_range ( dev , 4 * PAGE_SIZE , " cursor " , 1 ,
PAGE_SIZE ) ;
2012-05-21 15:27:30 +01:00
if ( ! cursor_gt ) {
2013-07-22 01:31:23 +02:00
gma_crtc - > cursor_gt = NULL ;
2012-05-21 15:27:30 +01:00
goto out ;
}
2013-07-22 01:31:23 +02:00
gma_crtc - > cursor_gt = cursor_gt ;
gma_crtc - > cursor_addr = dev_priv - > stolen_base +
2012-05-21 15:27:30 +01:00
cursor_gt - > offset ;
} else {
2013-07-22 01:31:23 +02:00
gma_crtc - > cursor_gt = NULL ;
2012-05-21 15:27:30 +01:00
}
2011-11-03 18:22:15 +00:00
2012-05-21 15:27:30 +01:00
out :
2013-07-22 01:31:23 +02:00
REG_WRITE ( control [ gma_crtc - > pipe ] , 0 ) ;
REG_WRITE ( base [ gma_crtc - > pipe ] , 0 ) ;
2011-11-03 18:22:15 +00:00
}
void psb_intel_crtc_init ( struct drm_device * dev , int pipe ,
struct psb_intel_mode_device * mode_dev )
{
struct drm_psb_private * dev_priv = dev - > dev_private ;
2013-07-22 01:31:23 +02:00
struct gma_crtc * gma_crtc ;
2011-11-03 18:22:15 +00:00
int i ;
/* We allocate a extra array of drm_connector pointers
* for fbdev after the crtc */
2013-07-22 01:31:23 +02:00
gma_crtc = kzalloc ( sizeof ( struct gma_crtc ) +
( INTELFB_CONN_LIMIT * sizeof ( struct drm_connector * ) ) ,
GFP_KERNEL ) ;
if ( gma_crtc = = NULL )
2011-11-03 18:22:15 +00:00
return ;
2013-07-22 01:31:23 +02:00
gma_crtc - > crtc_state =
2011-11-03 18:22:15 +00:00
kzalloc ( sizeof ( struct psb_intel_crtc_state ) , GFP_KERNEL ) ;
2013-07-22 01:31:23 +02:00
if ( ! gma_crtc - > crtc_state ) {
2011-11-03 18:22:15 +00:00
dev_err ( dev - > dev , " Crtc state error: No memory \n " ) ;
2013-07-22 01:31:23 +02:00
kfree ( gma_crtc ) ;
2011-11-03 18:22:15 +00:00
return ;
}
/* Set the CRTC operations from the chip specific data */
2013-07-22 01:31:23 +02:00
drm_crtc_init ( dev , & gma_crtc - > base , dev_priv - > ops - > crtc_funcs ) ;
2011-11-03 18:22:15 +00:00
2013-06-30 21:39:00 +02:00
/* Set the CRTC clock functions from chip specific data */
2013-07-22 01:31:23 +02:00
gma_crtc - > clock_funcs = dev_priv - > ops - > clock_funcs ;
2013-06-30 21:39:00 +02:00
2013-07-22 01:31:23 +02:00
drm_mode_crtc_set_gamma_size ( & gma_crtc - > base , 256 ) ;
gma_crtc - > pipe = pipe ;
gma_crtc - > plane = pipe ;
2011-11-03 18:22:15 +00:00
2017-07-13 18:25:32 +02:00
for ( i = 0 ; i < 256 ; i + + )
2013-07-22 01:31:23 +02:00
gma_crtc - > lut_adj [ i ] = 0 ;
2011-11-03 18:22:15 +00:00
2013-07-22 01:31:23 +02:00
gma_crtc - > mode_dev = mode_dev ;
gma_crtc - > cursor_addr = 0 ;
2011-11-03 18:22:15 +00:00
2013-07-22 01:31:23 +02:00
drm_crtc_helper_add ( & gma_crtc - > base ,
2011-11-03 18:22:15 +00:00
dev_priv - > ops - > crtc_helper ) ;
/* Setup the array of drm_connector pointer array */
2013-07-22 01:31:23 +02:00
gma_crtc - > mode_set . crtc = & gma_crtc - > base ;
2011-11-03 18:22:15 +00:00
BUG_ON ( pipe > = ARRAY_SIZE ( dev_priv - > plane_to_crtc_mapping ) | |
2013-07-22 01:31:23 +02:00
dev_priv - > plane_to_crtc_mapping [ gma_crtc - > plane ] ! = NULL ) ;
dev_priv - > plane_to_crtc_mapping [ gma_crtc - > plane ] = & gma_crtc - > base ;
dev_priv - > pipe_to_crtc_mapping [ gma_crtc - > pipe ] = & gma_crtc - > base ;
gma_crtc - > mode_set . connectors = ( struct drm_connector * * ) ( gma_crtc + 1 ) ;
gma_crtc - > mode_set . num_connectors = 0 ;
psb_intel_cursor_init ( dev , gma_crtc ) ;
2012-08-13 16:31:24 +00:00
/* Set to true so that the pipe is forced off on initial config. */
2013-07-22 01:31:23 +02:00
gma_crtc - > active = true ;
2011-11-03 18:22:15 +00:00
}
struct drm_crtc * psb_intel_get_crtc_from_pipe ( struct drm_device * dev , int pipe )
{
struct drm_crtc * crtc = NULL ;
list_for_each_entry ( crtc , & dev - > mode_config . crtc_list , head ) {
2013-07-22 01:31:23 +02:00
struct gma_crtc * gma_crtc = to_gma_crtc ( crtc ) ;
if ( gma_crtc - > pipe = = pipe )
2011-11-03 18:22:15 +00:00
break ;
}
return crtc ;
}
2013-07-22 17:05:25 +02:00
int gma_connector_clones ( struct drm_device * dev , int type_mask )
2011-11-03 18:22:15 +00:00
{
int index_mask = 0 ;
struct drm_connector * connector ;
int entry = 0 ;
list_for_each_entry ( connector , & dev - > mode_config . connector_list ,
head ) {
2013-07-22 17:45:26 +02:00
struct gma_encoder * gma_encoder = gma_attached_encoder ( connector ) ;
if ( type_mask & ( 1 < < gma_encoder - > type ) )
2011-11-03 18:22:15 +00:00
index_mask | = ( 1 < < entry ) ;
entry + + ;
}
return index_mask ;
}