2019-05-31 01:09:37 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2012-04-17 15:01:25 +01:00
/*
* Copyright 2010 Matt Turner .
* Copyright 2012 Red Hat
*
* Authors : Matthew Garrett
* Matt Turner
* Dave Airlie
*/
# include <linux/delay.h>
2019-12-03 11:04:00 +01:00
# include <linux/pci.h>
2012-04-17 15:01:25 +01:00
2020-05-15 10:32:32 +02:00
# include <drm/drm_atomic_helper.h>
# include <drm/drm_atomic_state_helper.h>
2012-10-02 18:01:07 +01:00
# include <drm/drm_crtc_helper.h>
2020-05-15 10:32:33 +02:00
# include <drm/drm_damage_helper.h>
# include <drm/drm_format_helper.h>
2019-06-23 12:35:42 +02:00
# include <drm/drm_fourcc.h>
2020-05-07 11:03:13 +02:00
# include <drm/drm_gem_framebuffer_helper.h>
2014-10-29 10:03:57 +01:00
# include <drm/drm_plane_helper.h>
2020-05-15 10:32:32 +02:00
# include <drm/drm_print.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2020-02-28 09:18:27 +01:00
# include <drm/drm_simple_kms_helper.h>
2012-04-17 15:01:25 +01:00
# include "mgag200_drv.h"
# define MGAG200_LUT_SIZE 256
/*
* This file contains setup code for the CRTC .
*/
static void mga_crtc_load_lut ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
2020-05-07 11:03:10 +02:00
struct mga_device * mdev = to_mga_device ( dev ) ;
2020-05-15 10:32:32 +02:00
struct drm_framebuffer * fb ;
2017-07-13 18:25:34 +02:00
u16 * r_ptr , * g_ptr , * b_ptr ;
2012-04-17 15:01:25 +01:00
int i ;
if ( ! crtc - > enabled )
return ;
2020-05-15 10:32:32 +02:00
if ( ! mdev - > display_pipe . plane . state )
return ;
fb = mdev - > display_pipe . plane . state - > fb ;
2017-07-13 18:25:34 +02:00
r_ptr = crtc - > gamma_store ;
g_ptr = r_ptr + crtc - > gamma_size ;
b_ptr = g_ptr + crtc - > gamma_size ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX + MGA1064_INDEX , 0 ) ;
2016-12-14 23:32:20 +02:00
if ( fb & & fb - > format - > cpp [ 0 ] * 8 = = 16 ) {
2016-12-14 23:31:35 +02:00
int inc = ( fb - > format - > depth = = 15 ) ? 8 : 4 ;
2013-07-17 15:07:27 +02:00
u8 r , b ;
for ( i = 0 ; i < MGAG200_LUT_SIZE ; i + = inc ) {
2016-12-14 23:31:35 +02:00
if ( fb - > format - > depth = = 16 ) {
2013-07-17 15:07:27 +02:00
if ( i > ( MGAG200_LUT_SIZE > > 1 ) ) {
r = b = 0 ;
} else {
2017-07-13 18:25:34 +02:00
r = * r_ptr + + > > 8 ;
b = * b_ptr + + > > 8 ;
r_ptr + + ;
b_ptr + + ;
2013-07-17 15:07:27 +02:00
}
} else {
2017-07-13 18:25:34 +02:00
r = * r_ptr + + > > 8 ;
b = * b_ptr + + > > 8 ;
2013-07-17 15:07:27 +02:00
}
/* VGA registers */
WREG8 ( DAC_INDEX + MGA1064_COL_PAL , r ) ;
2017-07-13 18:25:34 +02:00
WREG8 ( DAC_INDEX + MGA1064_COL_PAL , * g_ptr + + > > 8 ) ;
2013-07-17 15:07:27 +02:00
WREG8 ( DAC_INDEX + MGA1064_COL_PAL , b ) ;
}
return ;
}
2012-04-17 15:01:25 +01:00
for ( i = 0 ; i < MGAG200_LUT_SIZE ; i + + ) {
/* VGA registers */
2017-07-13 18:25:34 +02:00
WREG8 ( DAC_INDEX + MGA1064_COL_PAL , * r_ptr + + > > 8 ) ;
WREG8 ( DAC_INDEX + MGA1064_COL_PAL , * g_ptr + + > > 8 ) ;
WREG8 ( DAC_INDEX + MGA1064_COL_PAL , * b_ptr + + > > 8 ) ;
2012-04-17 15:01:25 +01:00
}
}
static inline void mga_wait_vsync ( struct mga_device * mdev )
{
2013-05-06 15:56:17 +00:00
unsigned long timeout = jiffies + HZ / 10 ;
2012-04-17 15:01:25 +01:00
unsigned int status = 0 ;
do {
status = RREG32 ( MGAREG_Status ) ;
2013-05-06 15:56:17 +00:00
} while ( ( status & 0x08 ) & & time_before ( jiffies , timeout ) ) ;
timeout = jiffies + HZ / 10 ;
2012-04-17 15:01:25 +01:00
status = 0 ;
do {
status = RREG32 ( MGAREG_Status ) ;
2013-05-06 15:56:17 +00:00
} while ( ! ( status & 0x08 ) & & time_before ( jiffies , timeout ) ) ;
2012-04-17 15:01:25 +01:00
}
static inline void mga_wait_busy ( struct mga_device * mdev )
{
2013-05-06 15:56:17 +00:00
unsigned long timeout = jiffies + HZ ;
2012-04-17 15:01:25 +01:00
unsigned int status = 0 ;
do {
status = RREG8 ( MGAREG_Status + 2 ) ;
2013-05-06 15:56:17 +00:00
} while ( ( status & 0x01 ) & & time_before ( jiffies , timeout ) ) ;
2012-04-17 15:01:25 +01:00
}
2015-08-21 09:24:13 -04:00
# define P_ARRAY_SIZE 9
2012-04-17 15:01:25 +01:00
static int mga_g200se_set_plls ( struct mga_device * mdev , long clock )
{
unsigned int vcomax , vcomin , pllreffreq ;
unsigned int delta , tmpdelta , permitteddelta ;
unsigned int testp , testm , testn ;
unsigned int p , m , n ;
unsigned int computed ;
2015-08-21 09:24:13 -04:00
unsigned int pvalues_e4 [ P_ARRAY_SIZE ] = { 16 , 14 , 12 , 10 , 8 , 6 , 4 , 2 , 1 } ;
unsigned int fvv ;
unsigned int i ;
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:13 -04:00
if ( mdev - > unique_rev_id < = 0x03 ) {
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:13 -04:00
m = n = p = 0 ;
vcomax = 320000 ;
vcomin = 160000 ;
pllreffreq = 25000 ;
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:13 -04:00
delta = 0xffffffff ;
permitteddelta = clock * 5 / 1000 ;
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:13 -04:00
for ( testp = 8 ; testp > 0 ; testp / = 2 ) {
if ( clock * testp > vcomax )
continue ;
if ( clock * testp < vcomin )
continue ;
for ( testn = 17 ; testn < 256 ; testn + + ) {
for ( testm = 1 ; testm < 32 ; testm + + ) {
computed = ( pllreffreq * testn ) /
( testm * testp ) ;
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
m = testm - 1 ;
n = testn - 1 ;
p = testp - 1 ;
}
}
}
}
} else {
m = n = p = 0 ;
vcomax = 1600000 ;
vcomin = 800000 ;
pllreffreq = 25000 ;
if ( clock < 25000 )
clock = 25000 ;
clock = clock * 2 ;
delta = 0xFFFFFFFF ;
/* Permited delta is 0.5% as VESA Specification */
permitteddelta = clock * 5 / 1000 ;
for ( i = 0 ; i < P_ARRAY_SIZE ; i + + ) {
testp = pvalues_e4 [ i ] ;
if ( ( clock * testp ) > vcomax )
continue ;
if ( ( clock * testp ) < vcomin )
continue ;
for ( testn = 50 ; testn < = 256 ; testn + + ) {
for ( testm = 1 ; testm < = 32 ; testm + + ) {
computed = ( pllreffreq * testn ) /
( testm * testp ) ;
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
m = testm - 1 ;
n = testn - 1 ;
p = testp - 1 ;
}
2012-04-17 15:01:25 +01:00
}
}
}
2015-08-21 09:24:13 -04:00
2016-05-27 15:12:50 -04:00
fvv = pllreffreq * ( n + 1 ) / ( m + 1 ) ;
2015-08-21 09:24:13 -04:00
fvv = ( fvv - 800000 ) / 50000 ;
if ( fvv > 15 )
fvv = 15 ;
p | = ( fvv < < 4 ) ;
m | = 0x80 ;
clock = clock / 2 ;
2012-04-17 15:01:25 +01:00
}
if ( delta > permitteddelta ) {
2017-02-28 04:55:54 -08:00
pr_warn ( " PLL delta too large \n " ) ;
2012-04-17 15:01:25 +01:00
return 1 ;
}
WREG_DAC ( MGA1064_PIX_PLLC_M , m ) ;
WREG_DAC ( MGA1064_PIX_PLLC_N , n ) ;
WREG_DAC ( MGA1064_PIX_PLLC_P , p ) ;
2016-05-27 15:12:50 -04:00
if ( mdev - > unique_rev_id > = 0x04 ) {
WREG_DAC ( 0x1a , 0x09 ) ;
msleep ( 20 ) ;
WREG_DAC ( 0x1a , 0x01 ) ;
}
2012-04-17 15:01:25 +01:00
return 0 ;
}
static int mga_g200wb_set_plls ( struct mga_device * mdev , long clock )
{
unsigned int vcomax , vcomin , pllreffreq ;
2015-07-01 17:12:45 +05:30
unsigned int delta , tmpdelta ;
2015-08-21 09:24:05 -04:00
unsigned int testp , testm , testn , testp2 ;
2012-04-17 15:01:25 +01:00
unsigned int p , m , n ;
unsigned int computed ;
int i , j , tmpcount , vcount ;
bool pll_locked = false ;
u8 tmp ;
m = n = p = 0 ;
delta = 0xffffffff ;
2015-08-21 09:24:05 -04:00
if ( mdev - > type = = G200_EW3 ) {
vcomax = 800000 ;
vcomin = 400000 ;
pllreffreq = 25000 ;
for ( testp = 1 ; testp < 8 ; testp + + ) {
for ( testp2 = 1 ; testp2 < 8 ; testp2 + + ) {
if ( testp < testp2 )
continue ;
if ( ( clock * testp * testp2 ) > vcomax )
continue ;
if ( ( clock * testp * testp2 ) < vcomin )
continue ;
for ( testm = 1 ; testm < 26 ; testm + + ) {
for ( testn = 32 ; testn < 2048 ; testn + + ) {
computed = ( pllreffreq * testn ) /
( testm * testp * testp2 ) ;
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
m = ( ( testn & 0x100 ) > > 1 ) |
( testm ) ;
n = ( testn & 0xFF ) ;
p = ( ( testn & 0x600 ) > > 3 ) |
( testp2 < < 3 ) |
( testp ) ;
}
}
}
}
}
} else {
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:05 -04:00
vcomax = 550000 ;
vcomin = 150000 ;
pllreffreq = 48000 ;
for ( testp = 1 ; testp < 9 ; testp + + ) {
if ( clock * testp > vcomax )
continue ;
if ( clock * testp < vcomin )
continue ;
for ( testm = 1 ; testm < 17 ; testm + + ) {
for ( testn = 1 ; testn < 151 ; testn + + ) {
computed = ( pllreffreq * testn ) /
( testm * testp ) ;
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
n = testn - 1 ;
m = ( testm - 1 ) |
( ( n > > 1 ) & 0x80 ) ;
p = testp - 1 ;
}
2012-04-17 15:01:25 +01:00
}
}
}
}
for ( i = 0 ; i < = 32 & & pll_locked = = false ; i + + ) {
if ( i > 0 ) {
WREG8 ( MGAREG_CRTC_INDEX , 0x1e ) ;
tmp = RREG8 ( MGAREG_CRTC_DATA ) ;
if ( tmp < 0xff )
WREG8 ( MGAREG_CRTC_DATA , tmp + 1 ) ;
}
/* set pixclkdis to 1 */
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_DIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX , MGA1064_REMHEADCTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_REMHEADCTL_CLKDIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
/* select PLL Set C */
tmp = RREG8 ( MGAREG_MEM_MISC_READ ) ;
tmp | = 0x3 < < 2 ;
WREG8 ( MGAREG_MEM_MISC_WRITE , tmp ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80 ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
udelay ( 500 ) ;
/* reset the PLL */
WREG8 ( DAC_INDEX , MGA1064_VREF_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ 0x04 ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
udelay ( 50 ) ;
/* program pixel pll register */
WREG_DAC ( MGA1064_WB_PIX_PLLC_N , n ) ;
WREG_DAC ( MGA1064_WB_PIX_PLLC_M , m ) ;
WREG_DAC ( MGA1064_WB_PIX_PLLC_P , p ) ;
udelay ( 50 ) ;
/* turn pll on */
WREG8 ( DAC_INDEX , MGA1064_VREF_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = 0x04 ;
WREG_DAC ( MGA1064_VREF_CTL , tmp ) ;
udelay ( 500 ) ;
/* select the pixel pll */
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_SEL_MSK ;
tmp | = MGA1064_PIX_CLK_CTL_SEL_PLL ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX , MGA1064_REMHEADCTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_REMHEADCTL_CLKSL_MSK ;
tmp | = MGA1064_REMHEADCTL_CLKSL_PLL ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
/* reset dotclock rate bit */
WREG8 ( MGAREG_SEQ_INDEX , 1 ) ;
tmp = RREG8 ( MGAREG_SEQ_DATA ) ;
tmp & = ~ 0x8 ;
WREG8 ( MGAREG_SEQ_DATA , tmp ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_CLK_DIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
vcount = RREG8 ( MGAREG_VCOUNT ) ;
for ( j = 0 ; j < 30 & & pll_locked = = false ; j + + ) {
tmpcount = RREG8 ( MGAREG_VCOUNT ) ;
if ( tmpcount < vcount )
vcount = 0 ;
if ( ( tmpcount - vcount ) > 2 )
pll_locked = true ;
else
udelay ( 5 ) ;
}
}
WREG8 ( DAC_INDEX , MGA1064_REMHEADCTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_REMHEADCTL_CLKDIS ;
WREG_DAC ( MGA1064_REMHEADCTL , tmp ) ;
return 0 ;
}
static int mga_g200ev_set_plls ( struct mga_device * mdev , long clock )
{
unsigned int vcomax , vcomin , pllreffreq ;
2015-07-01 17:12:45 +05:30
unsigned int delta , tmpdelta ;
2012-04-17 15:01:25 +01:00
unsigned int testp , testm , testn ;
unsigned int p , m , n ;
unsigned int computed ;
u8 tmp ;
m = n = p = 0 ;
vcomax = 550000 ;
vcomin = 150000 ;
pllreffreq = 50000 ;
delta = 0xffffffff ;
for ( testp = 16 ; testp > 0 ; testp - - ) {
if ( clock * testp > vcomax )
continue ;
if ( clock * testp < vcomin )
continue ;
for ( testn = 1 ; testn < 257 ; testn + + ) {
for ( testm = 1 ; testm < 17 ; testm + + ) {
computed = ( pllreffreq * testn ) /
( testm * testp ) ;
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
n = testn - 1 ;
m = testm - 1 ;
p = testp - 1 ;
}
}
}
}
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_DIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
tmp = RREG8 ( MGAREG_MEM_MISC_READ ) ;
tmp | = 0x3 < < 2 ;
WREG8 ( MGAREG_MEM_MISC_WRITE , tmp ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_PLL_STAT ) ;
tmp = RREG8 ( DAC_DATA ) ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp & ~ 0x40 ) ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
WREG_DAC ( MGA1064_EV_PIX_PLLC_M , m ) ;
WREG_DAC ( MGA1064_EV_PIX_PLLC_N , n ) ;
WREG_DAC ( MGA1064_EV_PIX_PLLC_P , p ) ;
udelay ( 50 ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
udelay ( 500 ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_SEL_MSK ;
tmp | = MGA1064_PIX_CLK_CTL_SEL_PLL ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX , MGA1064_PIX_PLL_STAT ) ;
tmp = RREG8 ( DAC_DATA ) ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp | 0x40 ) ;
2012-04-17 15:01:25 +01:00
tmp = RREG8 ( MGAREG_MEM_MISC_READ ) ;
tmp | = ( 0x3 < < 2 ) ;
WREG8 ( MGAREG_MEM_MISC_WRITE , tmp ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_CLK_DIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
return 0 ;
}
static int mga_g200eh_set_plls ( struct mga_device * mdev , long clock )
{
unsigned int vcomax , vcomin , pllreffreq ;
2015-07-01 17:12:45 +05:30
unsigned int delta , tmpdelta ;
2012-04-17 15:01:25 +01:00
unsigned int testp , testm , testn ;
unsigned int p , m , n ;
unsigned int computed ;
int i , j , tmpcount , vcount ;
u8 tmp ;
bool pll_locked = false ;
m = n = p = 0 ;
2016-10-21 12:47:07 -04:00
if ( mdev - > type = = G200_EH3 ) {
vcomax = 3000000 ;
vcomin = 1500000 ;
pllreffreq = 25000 ;
2012-04-17 15:01:25 +01:00
2016-10-21 12:47:07 -04:00
delta = 0xffffffff ;
2012-04-17 15:01:25 +01:00
2016-10-21 12:47:07 -04:00
testp = 0 ;
for ( testm = 150 ; testm > = 6 ; testm - - ) {
if ( clock * testm > vcomax )
continue ;
if ( clock * testm < vcomin )
continue ;
for ( testn = 120 ; testn > = 60 ; testn - - ) {
computed = ( pllreffreq * testn ) / testm ;
2012-04-17 15:01:25 +01:00
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
2016-10-21 12:47:07 -04:00
n = testn ;
m = testm ;
p = testp ;
}
if ( delta = = 0 )
break ;
}
if ( delta = = 0 )
break ;
}
} else {
vcomax = 800000 ;
vcomin = 400000 ;
pllreffreq = 33333 ;
delta = 0xffffffff ;
for ( testp = 16 ; testp > 0 ; testp > > = 1 ) {
if ( clock * testp > vcomax )
continue ;
if ( clock * testp < vcomin )
continue ;
for ( testm = 1 ; testm < 33 ; testm + + ) {
for ( testn = 17 ; testn < 257 ; testn + + ) {
computed = ( pllreffreq * testn ) /
( testm * testp ) ;
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
n = testn - 1 ;
m = ( testm - 1 ) ;
p = testp - 1 ;
}
if ( ( clock * testp ) > = 600000 )
p | = 0x80 ;
2012-04-17 15:01:25 +01:00
}
}
}
}
for ( i = 0 ; i < = 32 & & pll_locked = = false ; i + + ) {
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_DIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
tmp = RREG8 ( MGAREG_MEM_MISC_READ ) ;
tmp | = 0x3 < < 2 ;
WREG8 ( MGAREG_MEM_MISC_WRITE , tmp ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
udelay ( 500 ) ;
WREG_DAC ( MGA1064_EH_PIX_PLLC_M , m ) ;
WREG_DAC ( MGA1064_EH_PIX_PLLC_N , n ) ;
WREG_DAC ( MGA1064_EH_PIX_PLLC_P , p ) ;
udelay ( 500 ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_SEL_MSK ;
tmp | = MGA1064_PIX_CLK_CTL_SEL_PLL ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_CLK_DIS ;
tmp & = ~ MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
vcount = RREG8 ( MGAREG_VCOUNT ) ;
for ( j = 0 ; j < 30 & & pll_locked = = false ; j + + ) {
tmpcount = RREG8 ( MGAREG_VCOUNT ) ;
if ( tmpcount < vcount )
vcount = 0 ;
if ( ( tmpcount - vcount ) > 2 )
pll_locked = true ;
else
udelay ( 5 ) ;
}
}
return 0 ;
}
static int mga_g200er_set_plls ( struct mga_device * mdev , long clock )
{
unsigned int vcomax , vcomin , pllreffreq ;
unsigned int delta , tmpdelta ;
2012-08-09 15:00:15 +10:00
int testr , testn , testm , testo ;
2012-04-17 15:01:25 +01:00
unsigned int p , m , n ;
2012-08-09 15:00:15 +10:00
unsigned int computed , vco ;
2012-04-17 15:01:25 +01:00
int tmp ;
2012-08-09 15:00:15 +10:00
const unsigned int m_div_val [ ] = { 1 , 2 , 4 , 8 } ;
2012-04-17 15:01:25 +01:00
m = n = p = 0 ;
vcomax = 1488000 ;
vcomin = 1056000 ;
pllreffreq = 48000 ;
delta = 0xffffffff ;
for ( testr = 0 ; testr < 4 ; testr + + ) {
if ( delta = = 0 )
break ;
for ( testn = 5 ; testn < 129 ; testn + + ) {
if ( delta = = 0 )
break ;
for ( testm = 3 ; testm > = 0 ; testm - - ) {
if ( delta = = 0 )
break ;
for ( testo = 5 ; testo < 33 ; testo + + ) {
2012-08-09 15:00:15 +10:00
vco = pllreffreq * ( testn + 1 ) /
2012-04-17 15:01:25 +01:00
( testr + 1 ) ;
2012-08-09 15:00:15 +10:00
if ( vco < vcomin )
2012-04-17 15:01:25 +01:00
continue ;
2012-08-09 15:00:15 +10:00
if ( vco > vcomax )
2012-04-17 15:01:25 +01:00
continue ;
2012-08-09 15:00:15 +10:00
computed = vco / ( m_div_val [ testm ] * ( testo + 1 ) ) ;
2012-04-17 15:01:25 +01:00
if ( computed > clock )
tmpdelta = computed - clock ;
else
tmpdelta = clock - computed ;
if ( tmpdelta < delta ) {
delta = tmpdelta ;
m = testm | ( testo < < 3 ) ;
n = testn ;
p = testr | ( testr < < 3 ) ;
}
}
}
}
}
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_DIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
WREG8 ( DAC_INDEX , MGA1064_REMHEADCTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = MGA1064_REMHEADCTL_CLKDIS ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
tmp = RREG8 ( MGAREG_MEM_MISC_READ ) ;
tmp | = ( 0x3 < < 2 ) | 0xc0 ;
WREG8 ( MGAREG_MEM_MISC_WRITE , tmp ) ;
WREG8 ( DAC_INDEX , MGA1064_PIX_CLK_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ MGA1064_PIX_CLK_CTL_CLK_DIS ;
tmp | = MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ;
2013-04-12 22:24:05 +00:00
WREG8 ( DAC_DATA , tmp ) ;
2012-04-17 15:01:25 +01:00
udelay ( 500 ) ;
WREG_DAC ( MGA1064_ER_PIX_PLLC_N , n ) ;
WREG_DAC ( MGA1064_ER_PIX_PLLC_M , m ) ;
WREG_DAC ( MGA1064_ER_PIX_PLLC_P , p ) ;
udelay ( 50 ) ;
return 0 ;
}
2020-07-07 10:24:06 +02:00
static int mgag200_crtc_set_plls ( struct mga_device * mdev , long clock )
2012-04-17 15:01:25 +01:00
{
2020-05-15 10:32:23 +02:00
u8 misc ;
2012-04-17 15:01:25 +01:00
switch ( mdev - > type ) {
case G200_SE_A :
case G200_SE_B :
return mga_g200se_set_plls ( mdev , clock ) ;
break ;
case G200_WB :
2015-08-21 09:24:05 -04:00
case G200_EW3 :
2012-04-17 15:01:25 +01:00
return mga_g200wb_set_plls ( mdev , clock ) ;
break ;
case G200_EV :
return mga_g200ev_set_plls ( mdev , clock ) ;
break ;
case G200_EH :
2016-10-21 12:47:07 -04:00
case G200_EH3 :
2012-04-17 15:01:25 +01:00
return mga_g200eh_set_plls ( mdev , clock ) ;
break ;
case G200_ER :
return mga_g200er_set_plls ( mdev , clock ) ;
break ;
}
2020-05-15 10:32:23 +02:00
misc = RREG8 ( MGA_MISC_IN ) ;
misc & = ~ MGAREG_MISC_CLK_SEL_MASK ;
misc | = MGAREG_MISC_CLK_SEL_MGA_MSK ;
WREG8 ( MGA_MISC_OUT , misc ) ;
2012-04-17 15:01:25 +01:00
return 0 ;
}
static void mga_g200wb_prepare ( struct drm_crtc * crtc )
{
2020-05-07 11:03:10 +02:00
struct mga_device * mdev = to_mga_device ( crtc - > dev ) ;
2012-04-17 15:01:25 +01:00
u8 tmp ;
int iter_max ;
/* 1- The first step is to warn the BMC of an upcoming mode change.
* We are putting the misc < 0 > to output . */
WREG8 ( DAC_INDEX , MGA1064_GEN_IO_CTL ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = 0x10 ;
WREG_DAC ( MGA1064_GEN_IO_CTL , tmp ) ;
/* we are putting a 1 on the misc<0> line */
WREG8 ( DAC_INDEX , MGA1064_GEN_IO_DATA ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = 0x10 ;
WREG_DAC ( MGA1064_GEN_IO_DATA , tmp ) ;
/* 2- Second step to mask and further scan request
* This will be done by asserting the remfreqmsk bit ( XSPAREREG < 7 > )
*/
WREG8 ( DAC_INDEX , MGA1064_SPAREREG ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = 0x80 ;
WREG_DAC ( MGA1064_SPAREREG , tmp ) ;
/* 3a- the third step is to verifu if there is an active scan
* We are searching for a 0 on remhsyncsts < XSPAREREG < 0 > )
*/
iter_max = 300 ;
while ( ! ( tmp & 0x1 ) & & iter_max ) {
WREG8 ( DAC_INDEX , MGA1064_SPAREREG ) ;
tmp = RREG8 ( DAC_DATA ) ;
udelay ( 1000 ) ;
iter_max - - ;
}
/* 3b- this step occurs only if the remove is actually scanning
* we are waiting for the end of the frame which is a 1 on
* remvsyncsts ( XSPAREREG < 1 > )
*/
if ( iter_max ) {
iter_max = 300 ;
while ( ( tmp & 0x2 ) & & iter_max ) {
WREG8 ( DAC_INDEX , MGA1064_SPAREREG ) ;
tmp = RREG8 ( DAC_DATA ) ;
udelay ( 1000 ) ;
iter_max - - ;
}
}
}
static void mga_g200wb_commit ( struct drm_crtc * crtc )
{
u8 tmp ;
2020-05-07 11:03:10 +02:00
struct mga_device * mdev = to_mga_device ( crtc - > dev ) ;
2012-04-17 15:01:25 +01:00
/* 1- The first step is to ensure that the vrsten and hrsten are set */
WREG8 ( MGAREG_CRTCEXT_INDEX , 1 ) ;
tmp = RREG8 ( MGAREG_CRTCEXT_DATA ) ;
WREG8 ( MGAREG_CRTCEXT_DATA , tmp | 0x88 ) ;
/* 2- second step is to assert the rstlvl2 */
WREG8 ( DAC_INDEX , MGA1064_REMHEADCTL2 ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp | = 0x8 ;
WREG8 ( DAC_DATA , tmp ) ;
/* wait 10 us */
udelay ( 10 ) ;
/* 3- deassert rstlvl2 */
tmp & = ~ 0x08 ;
WREG8 ( DAC_INDEX , MGA1064_REMHEADCTL2 ) ;
WREG8 ( DAC_DATA , tmp ) ;
/* 4- remove mask of scan request */
WREG8 ( DAC_INDEX , MGA1064_SPAREREG ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ 0x80 ;
WREG8 ( DAC_DATA , tmp ) ;
/* 5- put back a 0 on the misc<0> line */
WREG8 ( DAC_INDEX , MGA1064_GEN_IO_DATA ) ;
tmp = RREG8 ( DAC_DATA ) ;
tmp & = ~ 0x10 ;
WREG_DAC ( MGA1064_GEN_IO_DATA , tmp ) ;
}
2013-05-08 19:10:38 +00:00
/*
2020-05-15 10:32:20 +02:00
* This is how the framebuffer base address is stored in g200 cards :
* * Assume @ offset is the gpu_addr variable of the framebuffer object
* * Then addr is the number of _pixels_ ( not bytes ) from the start of
* VRAM to the first pixel we want to display . ( divided by 2 for 32 bit
* framebuffers )
* * addr is stored in the CRTCEXT0 , CRTCC and CRTCD registers
* addr < 20 > - > CRTCEXT0 < 6 >
* addr < 19 - 16 > - > CRTCEXT0 < 3 - 0 >
* addr < 15 - 8 > - > CRTCC < 7 - 0 >
* addr < 7 - 0 > - > CRTCD < 7 - 0 >
*
* CRTCEXT0 has to be programmed last to trigger an update and make the
* new addr variable take effect .
2013-05-08 19:10:38 +00:00
*/
2020-05-15 10:32:20 +02:00
static void mgag200_set_startadd ( struct mga_device * mdev ,
unsigned long offset )
2012-04-17 15:01:25 +01:00
{
2020-06-05 15:58:02 +02:00
struct drm_device * dev = & mdev - > base ;
2020-05-15 10:32:20 +02:00
u32 startadd ;
u8 crtcc , crtcd , crtcext0 ;
2012-04-17 15:01:25 +01:00
2020-05-15 10:32:20 +02:00
startadd = offset / 8 ;
2012-04-17 15:01:25 +01:00
2020-05-15 10:32:20 +02:00
/*
* Can ' t store addresses any higher than that , but we also
* don ' t have more than 16 MiB of memory , so it should be fine .
*/
drm_WARN_ON ( dev , startadd > 0x1fffff ) ;
RREG_ECRT ( 0x00 , crtcext0 ) ;
crtcc = ( startadd > > 8 ) & 0xff ;
crtcd = startadd & 0xff ;
crtcext0 & = 0xb0 ;
crtcext0 | = ( ( startadd > > 14 ) & BIT ( 6 ) ) |
( ( startadd > > 16 ) & 0x0f ) ;
WREG_CRT ( 0x0c , crtcc ) ;
WREG_CRT ( 0x0d , crtcd ) ;
WREG_ECRT ( 0x00 , crtcext0 ) ;
2012-04-17 15:01:25 +01:00
}
2020-05-15 10:32:29 +02:00
static void mgag200_set_pci_regs ( struct mga_device * mdev )
{
uint32_t option = 0 , option2 = 0 ;
2020-06-05 15:58:02 +02:00
struct drm_device * dev = & mdev - > base ;
2020-05-15 10:32:29 +02:00
switch ( mdev - > type ) {
case G200_SE_A :
case G200_SE_B :
if ( mdev - > has_sdram )
option = 0x40049120 ;
else
option = 0x4004d120 ;
option2 = 0x00008000 ;
break ;
case G200_WB :
case G200_EW3 :
option = 0x41049120 ;
option2 = 0x0000b000 ;
break ;
case G200_EV :
option = 0x00000120 ;
option2 = 0x0000b000 ;
break ;
case G200_EH :
case G200_EH3 :
option = 0x00000120 ;
option2 = 0x0000b000 ;
break ;
case G200_ER :
break ;
}
if ( option )
pci_write_config_dword ( dev - > pdev , PCI_MGA_OPTION , option ) ;
if ( option2 )
pci_write_config_dword ( dev - > pdev , PCI_MGA_OPTION2 , option2 ) ;
}
static void mgag200_set_dac_regs ( struct mga_device * mdev )
{
size_t i ;
u8 dacvalue [ ] = {
/* 0x00: */ 0 , 0 , 0 , 0 , 0 , 0 , 0x00 , 0 ,
/* 0x08: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
/* 0x10: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
/* 0x18: */ 0x00 , 0 , 0xC9 , 0xFF , 0xBF , 0x20 , 0x1F , 0x20 ,
/* 0x20: */ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
/* 0x28: */ 0x00 , 0x00 , 0x00 , 0x00 , 0 , 0 , 0 , 0x40 ,
/* 0x30: */ 0x00 , 0xB0 , 0x00 , 0xC2 , 0x34 , 0x14 , 0x02 , 0x83 ,
/* 0x38: */ 0x00 , 0x93 , 0x00 , 0x77 , 0x00 , 0x00 , 0x00 , 0x3A ,
/* 0x40: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
/* 0x48: */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
switch ( mdev - > type ) {
case G200_SE_A :
case G200_SE_B :
dacvalue [ MGA1064_VREF_CTL ] = 0x03 ;
dacvalue [ MGA1064_PIX_CLK_CTL ] = MGA1064_PIX_CLK_CTL_SEL_PLL ;
dacvalue [ MGA1064_MISC_CTL ] = MGA1064_MISC_CTL_DAC_EN |
MGA1064_MISC_CTL_VGA8 |
MGA1064_MISC_CTL_DAC_RAM_CS ;
break ;
case G200_WB :
case G200_EW3 :
dacvalue [ MGA1064_VREF_CTL ] = 0x07 ;
break ;
case G200_EV :
dacvalue [ MGA1064_PIX_CLK_CTL ] = MGA1064_PIX_CLK_CTL_SEL_PLL ;
dacvalue [ MGA1064_MISC_CTL ] = MGA1064_MISC_CTL_VGA8 |
MGA1064_MISC_CTL_DAC_RAM_CS ;
break ;
case G200_EH :
case G200_EH3 :
dacvalue [ MGA1064_MISC_CTL ] = MGA1064_MISC_CTL_VGA8 |
MGA1064_MISC_CTL_DAC_RAM_CS ;
break ;
case G200_ER :
break ;
}
for ( i = 0 ; i < ARRAY_SIZE ( dacvalue ) ; i + + ) {
if ( ( i < = 0x17 ) | |
( i = = 0x1b ) | |
( i = = 0x1c ) | |
( ( i > = 0x1f ) & & ( i < = 0x29 ) ) | |
( ( i > = 0x30 ) & & ( i < = 0x37 ) ) )
continue ;
if ( IS_G200_SE ( mdev ) & &
( ( i = = 0x2c ) | | ( i = = 0x2d ) | | ( i = = 0x2e ) ) )
continue ;
if ( ( mdev - > type = = G200_EV | |
mdev - > type = = G200_WB | |
mdev - > type = = G200_EH | |
mdev - > type = = G200_EW3 | |
mdev - > type = = G200_EH3 ) & &
( i > = 0x44 ) & & ( i < = 0x4e ) )
continue ;
WREG_DAC ( i , dacvalue [ i ] ) ;
}
if ( mdev - > type = = G200_ER )
WREG_DAC ( 0x90 , 0 ) ;
}
static void mgag200_init_regs ( struct mga_device * mdev )
{
2020-07-07 10:24:05 +02:00
u8 crtc11 , crtcext3 , crtcext4 , misc ;
2020-05-15 10:32:29 +02:00
mgag200_set_pci_regs ( mdev ) ;
mgag200_set_dac_regs ( mdev ) ;
WREG_SEQ ( 2 , 0x0f ) ;
WREG_SEQ ( 3 , 0x00 ) ;
WREG_SEQ ( 4 , 0x0e ) ;
WREG_CRT ( 10 , 0 ) ;
WREG_CRT ( 11 , 0 ) ;
WREG_CRT ( 12 , 0 ) ;
WREG_CRT ( 13 , 0 ) ;
WREG_CRT ( 14 , 0 ) ;
WREG_CRT ( 15 , 0 ) ;
RREG_ECRT ( 0x03 , crtcext3 ) ;
crtcext3 | = BIT ( 7 ) ; /* enable MGA mode */
crtcext4 = 0x00 ;
WREG_ECRT ( 0x03 , crtcext3 ) ;
WREG_ECRT ( 0x04 , crtcext4 ) ;
2020-07-07 10:24:05 +02:00
RREG_CRT ( 0x11 , crtc11 ) ;
crtc11 & = ~ ( MGAREG_CRTC11_CRTCPROTECT |
MGAREG_CRTC11_VINTEN |
MGAREG_CRTC11_VINTCLR ) ;
WREG_CRT ( 0x11 , crtc11 ) ;
2020-05-15 10:32:29 +02:00
if ( mdev - > type = = G200_ER )
WREG_ECRT ( 0x24 , 0x5 ) ;
if ( mdev - > type = = G200_EW3 )
WREG_ECRT ( 0x34 , 0x5 ) ;
misc = RREG8 ( MGA_MISC_IN ) ;
misc | = MGAREG_MISC_IOADSEL |
MGAREG_MISC_RAMMAPEN |
MGAREG_MISC_HIGH_PG_SEL ;
WREG8 ( MGA_MISC_OUT , misc ) ;
}
2020-05-15 10:32:22 +02:00
static void mgag200_set_mode_regs ( struct mga_device * mdev ,
const struct drm_display_mode * mode )
{
unsigned int hdisplay , hsyncstart , hsyncend , htotal ;
unsigned int vdisplay , vsyncstart , vsyncend , vtotal ;
2020-05-15 10:32:23 +02:00
u8 misc , crtcext1 , crtcext2 , crtcext5 ;
2020-05-15 10:32:22 +02:00
hdisplay = mode - > hdisplay / 8 - 1 ;
hsyncstart = mode - > hsync_start / 8 - 1 ;
hsyncend = mode - > hsync_end / 8 - 1 ;
htotal = mode - > htotal / 8 - 1 ;
/* Work around hardware quirk */
if ( ( htotal & 0x07 ) = = 0x06 | | ( htotal & 0x07 ) = = 0x04 )
htotal + + ;
vdisplay = mode - > vdisplay - 1 ;
vsyncstart = mode - > vsync_start - 1 ;
vsyncend = mode - > vsync_end - 1 ;
vtotal = mode - > vtotal - 2 ;
2020-05-15 10:32:23 +02:00
misc = RREG8 ( MGA_MISC_IN ) ;
2020-05-15 10:32:22 +02:00
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
2020-05-15 10:32:23 +02:00
misc | = MGAREG_MISC_HSYNCPOL ;
else
misc & = ~ MGAREG_MISC_HSYNCPOL ;
2020-05-15 10:32:22 +02:00
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
2020-05-15 10:32:23 +02:00
misc | = MGAREG_MISC_VSYNCPOL ;
else
misc & = ~ MGAREG_MISC_VSYNCPOL ;
2020-05-15 10:32:22 +02:00
crtcext1 = ( ( ( htotal - 4 ) & 0x100 ) > > 8 ) |
( ( hdisplay & 0x100 ) > > 7 ) |
( ( hsyncstart & 0x100 ) > > 6 ) |
( htotal & 0x40 ) ;
if ( mdev - > type = = G200_WB | | mdev - > type = = G200_EW3 )
crtcext1 | = BIT ( 7 ) | /* vrsten */
BIT ( 3 ) ; /* hrsten */
crtcext2 = ( ( vtotal & 0xc00 ) > > 10 ) |
( ( vdisplay & 0x400 ) > > 8 ) |
( ( vdisplay & 0xc00 ) > > 7 ) |
( ( vsyncstart & 0xc00 ) > > 5 ) |
( ( vdisplay & 0x400 ) > > 3 ) ;
crtcext5 = 0x00 ;
WREG_CRT ( 0 , htotal - 4 ) ;
WREG_CRT ( 1 , hdisplay ) ;
WREG_CRT ( 2 , hdisplay ) ;
WREG_CRT ( 3 , ( htotal & 0x1F ) | 0x80 ) ;
WREG_CRT ( 4 , hsyncstart ) ;
WREG_CRT ( 5 , ( ( htotal & 0x20 ) < < 2 ) | ( hsyncend & 0x1F ) ) ;
WREG_CRT ( 6 , vtotal & 0xFF ) ;
WREG_CRT ( 7 , ( ( vtotal & 0x100 ) > > 8 ) |
( ( vdisplay & 0x100 ) > > 7 ) |
( ( vsyncstart & 0x100 ) > > 6 ) |
( ( vdisplay & 0x100 ) > > 5 ) |
( ( vdisplay & 0x100 ) > > 4 ) | /* linecomp */
( ( vtotal & 0x200 ) > > 4 ) |
( ( vdisplay & 0x200 ) > > 3 ) |
( ( vsyncstart & 0x200 ) > > 2 ) ) ;
WREG_CRT ( 9 , ( ( vdisplay & 0x200 ) > > 4 ) |
( ( vdisplay & 0x200 ) > > 3 ) ) ;
WREG_CRT ( 16 , vsyncstart & 0xFF ) ;
WREG_CRT ( 17 , ( vsyncend & 0x0F ) | 0x20 ) ;
WREG_CRT ( 18 , vdisplay & 0xFF ) ;
WREG_CRT ( 20 , 0 ) ;
WREG_CRT ( 21 , vdisplay & 0xFF ) ;
WREG_CRT ( 22 , ( vtotal + 1 ) & 0xFF ) ;
WREG_CRT ( 23 , 0xc3 ) ;
WREG_CRT ( 24 , vdisplay & 0xFF ) ;
WREG_ECRT ( 0x01 , crtcext1 ) ;
WREG_ECRT ( 0x02 , crtcext2 ) ;
WREG_ECRT ( 0x05 , crtcext5 ) ;
2020-05-15 10:32:23 +02:00
WREG8 ( MGA_MISC_OUT , misc ) ;
2020-05-15 10:32:22 +02:00
}
2020-05-15 10:32:25 +02:00
static u8 mgag200_get_bpp_shift ( struct mga_device * mdev ,
const struct drm_format_info * format )
{
return mdev - > bpp_shifts [ format - > cpp [ 0 ] - 1 ] ;
}
/*
* Calculates the HW offset value from the framebuffer ' s pitch . The
* offset is a multiple of the pixel size and depends on the display
* format .
*/
static u32 mgag200_calculate_offset ( struct mga_device * mdev ,
const struct drm_framebuffer * fb )
{
u32 offset = fb - > pitches [ 0 ] / fb - > format - > cpp [ 0 ] ;
u8 bppshift = mgag200_get_bpp_shift ( mdev , fb - > format ) ;
if ( fb - > format - > cpp [ 0 ] * 8 = = 24 )
offset = ( offset * 3 ) > > ( 4 - bppshift ) ;
else
offset = offset > > ( 4 - bppshift ) ;
return offset ;
}
static void mgag200_set_offset ( struct mga_device * mdev ,
const struct drm_framebuffer * fb )
{
u8 crtc13 , crtcext0 ;
u32 offset = mgag200_calculate_offset ( mdev , fb ) ;
RREG_ECRT ( 0 , crtcext0 ) ;
crtc13 = offset & 0xff ;
crtcext0 & = ~ MGAREG_CRTCEXT0_OFFSET_MASK ;
crtcext0 | = ( offset > > 4 ) & MGAREG_CRTCEXT0_OFFSET_MASK ;
WREG_CRT ( 0x13 , crtc13 ) ;
WREG_ECRT ( 0x00 , crtcext0 ) ;
}
2020-05-15 10:32:26 +02:00
static void mgag200_set_format_regs ( struct mga_device * mdev ,
const struct drm_framebuffer * fb )
{
2020-06-05 15:58:02 +02:00
struct drm_device * dev = & mdev - > base ;
2020-05-15 10:32:26 +02:00
const struct drm_format_info * format = fb - > format ;
unsigned int bpp , bppshift , scale ;
u8 crtcext3 , xmulctrl ;
bpp = format - > cpp [ 0 ] * 8 ;
bppshift = mgag200_get_bpp_shift ( mdev , format ) ;
switch ( bpp ) {
case 24 :
scale = ( ( 1 < < bppshift ) * 3 ) - 1 ;
break ;
default :
scale = ( 1 < < bppshift ) - 1 ;
break ;
}
RREG_ECRT ( 3 , crtcext3 ) ;
switch ( bpp ) {
case 8 :
xmulctrl = MGA1064_MUL_CTL_8bits ;
break ;
case 16 :
if ( format - > depth = = 15 )
xmulctrl = MGA1064_MUL_CTL_15bits ;
else
xmulctrl = MGA1064_MUL_CTL_16bits ;
break ;
case 24 :
xmulctrl = MGA1064_MUL_CTL_24bits ;
break ;
case 32 :
xmulctrl = MGA1064_MUL_CTL_32_24bits ;
break ;
default :
/* BUG: We should have caught this problem already. */
drm_WARN_ON ( dev , " invalid format depth \n " ) ;
return ;
}
crtcext3 & = ~ GENMASK ( 2 , 0 ) ;
crtcext3 | = scale ;
WREG_DAC ( MGA1064_MUL_CTL , xmulctrl ) ;
WREG_GFX ( 0 , 0x00 ) ;
WREG_GFX ( 1 , 0x00 ) ;
WREG_GFX ( 2 , 0x00 ) ;
WREG_GFX ( 3 , 0x00 ) ;
WREG_GFX ( 4 , 0x00 ) ;
WREG_GFX ( 5 , 0x40 ) ;
WREG_GFX ( 6 , 0x05 ) ;
WREG_GFX ( 7 , 0x0f ) ;
WREG_GFX ( 8 , 0x0f ) ;
WREG_ECRT ( 3 , crtcext3 ) ;
}
2020-05-15 10:32:27 +02:00
static void mgag200_g200er_reset_tagfifo ( struct mga_device * mdev )
{
static uint32_t RESET_FLAG = 0x00200000 ; /* undocumented magic value */
u32 memctl ;
memctl = RREG32 ( MGAREG_MEMCTL ) ;
memctl | = RESET_FLAG ;
WREG32 ( MGAREG_MEMCTL , memctl ) ;
udelay ( 1000 ) ;
memctl & = ~ RESET_FLAG ;
WREG32 ( MGAREG_MEMCTL , memctl ) ;
}
2020-05-15 10:32:28 +02:00
static void mgag200_g200se_set_hiprilvl ( struct mga_device * mdev ,
const struct drm_display_mode * mode ,
const struct drm_framebuffer * fb )
{
unsigned int hiprilvl ;
u8 crtcext6 ;
if ( mdev - > unique_rev_id > = 0x04 ) {
hiprilvl = 0 ;
} else if ( mdev - > unique_rev_id > = 0x02 ) {
unsigned int bpp ;
unsigned long mb ;
if ( fb - > format - > cpp [ 0 ] * 8 > 16 )
bpp = 32 ;
else if ( fb - > format - > cpp [ 0 ] * 8 > 8 )
bpp = 16 ;
else
bpp = 8 ;
mb = ( mode - > clock * bpp ) / 1000 ;
if ( mb > 3100 )
hiprilvl = 0 ;
else if ( mb > 2600 )
hiprilvl = 1 ;
else if ( mb > 1900 )
hiprilvl = 2 ;
else if ( mb > 1160 )
hiprilvl = 3 ;
else if ( mb > 440 )
hiprilvl = 4 ;
else
hiprilvl = 5 ;
} else if ( mdev - > unique_rev_id > = 0x01 ) {
hiprilvl = 3 ;
} else {
hiprilvl = 4 ;
}
crtcext6 = hiprilvl ; /* implicitly sets maxhipri to 0 */
WREG_ECRT ( 0x06 , crtcext6 ) ;
}
static void mgag200_g200ev_set_hiprilvl ( struct mga_device * mdev )
{
WREG_ECRT ( 0x06 , 0x00 ) ;
}
2020-07-07 10:24:08 +02:00
static void mgag200_enable_display ( struct mga_device * mdev )
2012-04-17 15:01:25 +01:00
{
2020-07-07 10:24:09 +02:00
u8 seq0 , seq1 , crtcext1 ;
RREG_SEQ ( 0x00 , seq0 ) ;
seq0 | = MGAREG_SEQ0_SYNCRST |
MGAREG_SEQ0_ASYNCRST ;
WREG_SEQ ( 0x00 , seq0 ) ;
2012-04-17 15:01:25 +01:00
2020-07-07 10:24:08 +02:00
/*
* TODO : replace busy waiting with vblank IRQ ; put
* msleep ( 50 ) before changing SCROFF
*/
mga_wait_vsync ( mdev ) ;
mga_wait_busy ( mdev ) ;
RREG_SEQ ( 0x01 , seq1 ) ;
seq1 & = ~ MGAREG_SEQ1_SCROFF ;
WREG_SEQ ( 0x01 , seq1 ) ;
msleep ( 20 ) ;
RREG_ECRT ( 0x01 , crtcext1 ) ;
crtcext1 & = ~ MGAREG_CRTCEXT1_VSYNCOFF ;
crtcext1 & = ~ MGAREG_CRTCEXT1_HSYNCOFF ;
WREG_ECRT ( 0x01 , crtcext1 ) ;
}
2012-04-17 15:01:25 +01:00
2020-07-07 10:24:08 +02:00
static void mgag200_disable_display ( struct mga_device * mdev )
{
2020-07-07 10:24:09 +02:00
u8 seq0 , seq1 , crtcext1 ;
RREG_SEQ ( 0x00 , seq0 ) ;
seq0 & = ~ MGAREG_SEQ0_SYNCRST ;
WREG_SEQ ( 0x00 , seq0 ) ;
2020-07-07 10:24:08 +02:00
/*
* TODO : replace busy waiting with vblank IRQ ; put
* msleep ( 50 ) before changing SCROFF
*/
2012-04-17 15:01:25 +01:00
mga_wait_vsync ( mdev ) ;
mga_wait_busy ( mdev ) ;
2020-07-07 10:24:08 +02:00
RREG_SEQ ( 0x01 , seq1 ) ;
seq1 | = MGAREG_SEQ1_SCROFF ;
WREG_SEQ ( 0x01 , seq1 ) ;
2012-04-17 15:01:25 +01:00
msleep ( 20 ) ;
2020-07-07 10:24:08 +02:00
RREG_ECRT ( 0x01 , crtcext1 ) ;
crtcext1 | = MGAREG_CRTCEXT1_VSYNCOFF |
MGAREG_CRTCEXT1_HSYNCOFF ;
WREG_ECRT ( 0x01 , crtcext1 ) ;
2012-04-17 15:01:25 +01:00
}
/*
* This is called before a mode is programmed . A typical use might be to
* enable DPMS during the programming to avoid seeing intermediate stages ,
* but that ' s not relevant to us
*/
static void mga_crtc_prepare ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
2020-05-07 11:03:10 +02:00
struct mga_device * mdev = to_mga_device ( dev ) ;
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:05 -04:00
if ( mdev - > type = = G200_WB | | mdev - > type = = G200_EW3 )
2012-04-17 15:01:25 +01:00
mga_g200wb_prepare ( crtc ) ;
}
/*
* This is called after a mode is programmed . It should reverse anything done
* by the prepare function
*/
static void mga_crtc_commit ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
2020-05-07 11:03:10 +02:00
struct mga_device * mdev = to_mga_device ( dev ) ;
2012-04-17 15:01:25 +01:00
2015-08-21 09:24:05 -04:00
if ( mdev - > type = = G200_WB | | mdev - > type = = G200_EW3 )
2012-04-17 15:01:25 +01:00
mga_g200wb_commit ( crtc ) ;
2020-07-07 10:24:08 +02:00
mga_crtc_load_lut ( crtc ) ;
mgag200_enable_display ( mdev ) ;
2012-04-17 15:01:25 +01:00
}
2020-05-07 11:03:15 +02:00
/*
* Connector
*/
2012-04-17 15:01:25 +01:00
static int mga_vga_get_modes ( struct drm_connector * connector )
{
struct mga_connector * mga_connector = to_mga_connector ( connector ) ;
struct edid * edid ;
int ret = 0 ;
edid = drm_get_edid ( connector , & mga_connector - > i2c - > adapter ) ;
if ( edid ) {
2018-07-09 10:40:06 +02:00
drm_connector_update_edid_property ( connector , edid ) ;
2012-04-17 15:01:25 +01:00
ret = drm_add_edid_modes ( connector , edid ) ;
kfree ( edid ) ;
}
return ret ;
}
2013-06-27 13:38:59 -04:00
static uint32_t mga_vga_calculate_mode_bandwidth ( struct drm_display_mode * mode ,
int bits_per_pixel )
{
uint32_t total_area , divisor ;
2015-11-03 23:09:58 -05:00
uint64_t active_area , pixels_per_second , bandwidth ;
2013-06-27 13:38:59 -04:00
uint64_t bytes_per_pixel = ( bits_per_pixel + 7 ) / 8 ;
divisor = 1024 ;
if ( ! mode - > htotal | | ! mode - > vtotal | | ! mode - > clock )
return 0 ;
active_area = mode - > hdisplay * mode - > vdisplay ;
total_area = mode - > htotal * mode - > vtotal ;
pixels_per_second = active_area * mode - > clock * 1000 ;
do_div ( pixels_per_second , total_area ) ;
bandwidth = pixels_per_second * bytes_per_pixel * 100 ;
do_div ( bandwidth , divisor ) ;
return ( uint32_t ) ( bandwidth ) ;
}
# define MODE_BANDWIDTH MODE_BAD
2018-04-24 15:15:06 +02:00
static enum drm_mode_status mga_vga_mode_valid ( struct drm_connector * connector ,
2012-04-17 15:01:25 +01:00
struct drm_display_mode * mode )
{
2013-02-26 10:55:44 -05:00
struct drm_device * dev = connector - > dev ;
2020-05-07 11:03:10 +02:00
struct mga_device * mdev = to_mga_device ( dev ) ;
2013-02-26 10:55:44 -05:00
int bpp = 32 ;
2013-06-27 13:38:59 -04:00
if ( IS_G200_SE ( mdev ) ) {
if ( mdev - > unique_rev_id = = 0x01 ) {
if ( mode - > hdisplay > 1600 )
return MODE_VIRTUAL_X ;
if ( mode - > vdisplay > 1200 )
return MODE_VIRTUAL_Y ;
if ( mga_vga_calculate_mode_bandwidth ( mode , bpp )
> ( 24400 * 1024 ) )
return MODE_BANDWIDTH ;
2015-08-21 09:24:13 -04:00
} else if ( mdev - > unique_rev_id = = 0x02 ) {
2013-06-27 13:38:59 -04:00
if ( mode - > hdisplay > 1920 )
return MODE_VIRTUAL_X ;
if ( mode - > vdisplay > 1200 )
return MODE_VIRTUAL_Y ;
if ( mga_vga_calculate_mode_bandwidth ( mode , bpp )
> ( 30100 * 1024 ) )
return MODE_BANDWIDTH ;
2017-06-14 10:39:42 -04:00
} else {
if ( mga_vga_calculate_mode_bandwidth ( mode , bpp )
> ( 55000 * 1024 ) )
return MODE_BANDWIDTH ;
2013-06-27 13:38:59 -04:00
}
} else if ( mdev - > type = = G200_WB ) {
if ( mode - > hdisplay > 1280 )
return MODE_VIRTUAL_X ;
if ( mode - > vdisplay > 1024 )
return MODE_VIRTUAL_Y ;
2018-01-25 17:26:55 +03:00
if ( mga_vga_calculate_mode_bandwidth ( mode , bpp ) >
( 31877 * 1024 ) )
2013-06-27 13:38:59 -04:00
return MODE_BANDWIDTH ;
} else if ( mdev - > type = = G200_EV & &
( mga_vga_calculate_mode_bandwidth ( mode , bpp )
> ( 32700 * 1024 ) ) ) {
return MODE_BANDWIDTH ;
2014-02-05 14:13:56 +10:00
} else if ( mdev - > type = = G200_EH & &
2013-06-27 13:38:59 -04:00
( mga_vga_calculate_mode_bandwidth ( mode , bpp )
> ( 37500 * 1024 ) ) ) {
return MODE_BANDWIDTH ;
2014-02-05 14:13:56 +10:00
} else if ( mdev - > type = = G200_ER & &
2013-06-27 13:38:59 -04:00
( mga_vga_calculate_mode_bandwidth ( mode ,
bpp ) > ( 55000 * 1024 ) ) ) {
return MODE_BANDWIDTH ;
}
2012-04-17 15:01:25 +01:00
2015-06-15 16:16:15 -04:00
if ( ( mode - > hdisplay % 8 ) ! = 0 | | ( mode - > hsync_start % 8 ) ! = 0 | |
( mode - > hsync_end % 8 ) ! = 0 | | ( mode - > htotal % 8 ) ! = 0 ) {
return MODE_H_ILLEGAL ;
}
2012-04-17 15:01:25 +01:00
if ( mode - > crtc_hdisplay > 2048 | | mode - > crtc_hsync_start > 4096 | |
mode - > crtc_hsync_end > 4096 | | mode - > crtc_htotal > 4096 | |
mode - > crtc_vdisplay > 2048 | | mode - > crtc_vsync_start > 4096 | |
mode - > crtc_vsync_end > 4096 | | mode - > crtc_vtotal > 4096 ) {
return MODE_BAD ;
}
2013-02-26 10:55:44 -05:00
/* Validate the mode input by the user */
2014-08-06 10:08:32 +02:00
if ( connector - > cmdline_mode . specified ) {
if ( connector - > cmdline_mode . bpp_specified )
bpp = connector - > cmdline_mode . bpp ;
2013-02-26 10:55:44 -05:00
}
2019-09-27 11:13:00 +02:00
if ( ( mode - > hdisplay * mode - > vdisplay * ( bpp / 8 ) ) > mdev - > vram_fb_available ) {
2014-08-06 10:08:32 +02:00
if ( connector - > cmdline_mode . specified )
connector - > cmdline_mode . specified = false ;
2013-02-26 10:55:44 -05:00
return MODE_BAD ;
}
2012-04-17 15:01:25 +01:00
return MODE_OK ;
}
static void mga_connector_destroy ( struct drm_connector * connector )
{
struct mga_connector * mga_connector = to_mga_connector ( connector ) ;
mgag200_i2c_destroy ( mga_connector - > i2c ) ;
drm_connector_cleanup ( connector ) ;
}
2015-12-15 12:21:10 +01:00
static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
2020-05-15 10:32:32 +02:00
. get_modes = mga_vga_get_modes ,
2012-04-17 15:01:25 +01:00
. mode_valid = mga_vga_mode_valid ,
} ;
2015-12-15 12:21:10 +01:00
static const struct drm_connector_funcs mga_vga_connector_funcs = {
2020-05-15 10:32:32 +02:00
. reset = drm_atomic_helper_connector_reset ,
. fill_modes = drm_helper_probe_single_connector_modes ,
. destroy = mga_connector_destroy ,
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
2012-04-17 15:01:25 +01:00
} ;
2020-05-07 11:03:15 +02:00
static int mgag200_vga_connector_init ( struct mga_device * mdev )
2012-04-17 15:01:25 +01:00
{
2020-06-05 15:58:02 +02:00
struct drm_device * dev = & mdev - > base ;
2020-05-07 11:03:15 +02:00
struct mga_connector * mconnector = & mdev - > connector ;
struct drm_connector * connector = & mconnector - > base ;
struct mga_i2c_chan * i2c ;
int ret ;
2012-04-17 15:01:25 +01:00
2020-05-07 11:03:15 +02:00
i2c = mgag200_i2c_create ( dev ) ;
if ( ! i2c )
drm_warn ( dev , " failed to add DDC bus \n " ) ;
2012-04-17 15:01:25 +01:00
2020-05-07 11:03:15 +02:00
ret = drm_connector_init_with_ddc ( dev , connector ,
& mga_vga_connector_funcs ,
DRM_MODE_CONNECTOR_VGA ,
& i2c - > adapter ) ;
if ( ret )
goto err_mgag200_i2c_destroy ;
2012-04-17 15:01:25 +01:00
drm_connector_helper_add ( connector , & mga_vga_connector_helper_funcs ) ;
2020-05-07 11:03:15 +02:00
mconnector - > i2c = i2c ;
2013-07-17 15:07:25 +02:00
2020-05-07 11:03:15 +02:00
return 0 ;
err_mgag200_i2c_destroy :
mgag200_i2c_destroy ( i2c ) ;
return ret ;
2012-04-17 15:01:25 +01:00
}
2020-05-15 10:32:32 +02:00
/*
* Simple Display Pipe
*/
static enum drm_mode_status
mgag200_simple_display_pipe_mode_valid ( struct drm_simple_display_pipe * pipe ,
const struct drm_display_mode * mode )
{
return MODE_OK ;
}
2020-05-15 10:32:33 +02:00
static void
mgag200_handle_damage ( struct mga_device * mdev , struct drm_framebuffer * fb ,
struct drm_rect * clip )
{
2020-06-05 15:58:02 +02:00
struct drm_device * dev = & mdev - > base ;
2020-05-15 10:32:33 +02:00
void * vmap ;
vmap = drm_gem_shmem_vmap ( fb - > obj [ 0 ] ) ;
if ( drm_WARN_ON ( dev , ! vmap ) )
return ; /* BUG: SHMEM BO should always be vmapped */
drm_fb_memcpy_dstclip ( mdev - > vram , vmap , fb , clip ) ;
drm_gem_shmem_vunmap ( fb - > obj [ 0 ] , vmap ) ;
/* Always scanout image at VRAM offset 0 */
mgag200_set_startadd ( mdev , ( u32 ) 0 ) ;
mgag200_set_offset ( mdev , fb ) ;
}
2020-05-15 10:32:32 +02:00
static void
mgag200_simple_display_pipe_enable ( struct drm_simple_display_pipe * pipe ,
struct drm_crtc_state * crtc_state ,
struct drm_plane_state * plane_state )
{
struct drm_crtc * crtc = & pipe - > crtc ;
struct drm_device * dev = crtc - > dev ;
struct mga_device * mdev = to_mga_device ( dev ) ;
struct drm_display_mode * adjusted_mode = & crtc_state - > adjusted_mode ;
struct drm_framebuffer * fb = plane_state - > fb ;
2020-05-15 10:32:33 +02:00
struct drm_rect fullscreen = {
. x1 = 0 ,
. x2 = fb - > width ,
. y1 = 0 ,
. y2 = fb - > height ,
} ;
2020-05-15 10:32:32 +02:00
mga_crtc_prepare ( crtc ) ;
mgag200_set_format_regs ( mdev , fb ) ;
mgag200_set_mode_regs ( mdev , adjusted_mode ) ;
2020-07-07 10:24:06 +02:00
mgag200_crtc_set_plls ( mdev , adjusted_mode - > clock ) ;
2020-05-15 10:32:32 +02:00
if ( mdev - > type = = G200_ER )
mgag200_g200er_reset_tagfifo ( mdev ) ;
if ( IS_G200_SE ( mdev ) )
mgag200_g200se_set_hiprilvl ( mdev , adjusted_mode , fb ) ;
else if ( mdev - > type = = G200_EV )
mgag200_g200ev_set_hiprilvl ( mdev ) ;
mga_crtc_commit ( crtc ) ;
2020-05-15 10:32:33 +02:00
mgag200_handle_damage ( mdev , fb , & fullscreen ) ;
2020-05-15 10:32:32 +02:00
}
static void
mgag200_simple_display_pipe_disable ( struct drm_simple_display_pipe * pipe )
{
struct drm_crtc * crtc = & pipe - > crtc ;
2020-07-07 10:24:08 +02:00
struct mga_device * mdev = to_mga_device ( crtc - > dev ) ;
2020-05-15 10:32:32 +02:00
2020-07-07 10:24:08 +02:00
mgag200_disable_display ( mdev ) ;
2020-05-15 10:32:32 +02:00
}
static int
mgag200_simple_display_pipe_check ( struct drm_simple_display_pipe * pipe ,
struct drm_plane_state * plane_state ,
struct drm_crtc_state * crtc_state )
{
struct drm_plane * plane = plane_state - > plane ;
struct drm_framebuffer * new_fb = plane_state - > fb ;
struct drm_framebuffer * fb = NULL ;
if ( ! new_fb )
return 0 ;
if ( plane - > state )
fb = plane - > state - > fb ;
if ( ! fb | | ( fb - > format ! = new_fb - > format ) )
crtc_state - > mode_changed = true ; /* update PLL settings */
return 0 ;
}
static void
mgag200_simple_display_pipe_update ( struct drm_simple_display_pipe * pipe ,
struct drm_plane_state * old_state )
{
struct drm_plane * plane = & pipe - > plane ;
struct drm_device * dev = plane - > dev ;
struct mga_device * mdev = to_mga_device ( dev ) ;
struct drm_plane_state * state = plane - > state ;
struct drm_framebuffer * fb = state - > fb ;
2020-05-15 10:32:33 +02:00
struct drm_rect damage ;
2020-05-15 10:32:32 +02:00
if ( ! fb )
return ;
2020-05-15 10:32:33 +02:00
if ( drm_atomic_helper_damage_merged ( old_state , state , & damage ) )
mgag200_handle_damage ( mdev , fb , & damage ) ;
2020-05-15 10:32:32 +02:00
}
static const struct drm_simple_display_pipe_funcs
mgag200_simple_display_pipe_funcs = {
. mode_valid = mgag200_simple_display_pipe_mode_valid ,
. enable = mgag200_simple_display_pipe_enable ,
. disable = mgag200_simple_display_pipe_disable ,
. check = mgag200_simple_display_pipe_check ,
. update = mgag200_simple_display_pipe_update ,
2020-05-15 10:32:33 +02:00
. prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb ,
2020-05-15 10:32:32 +02:00
} ;
static const uint32_t mgag200_simple_display_pipe_formats [ ] = {
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_RGB888 ,
} ;
static const uint64_t mgag200_simple_display_pipe_fmtmods [ ] = {
DRM_FORMAT_MOD_LINEAR ,
DRM_FORMAT_MOD_INVALID
} ;
/*
* Mode config
*/
2020-05-07 11:03:13 +02:00
static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
2020-05-15 10:32:33 +02:00
. fb_create = drm_gem_fb_create_with_dirty ,
2020-05-15 10:32:32 +02:00
. atomic_check = drm_atomic_helper_check ,
. atomic_commit = drm_atomic_helper_commit ,
2020-05-07 11:03:13 +02:00
} ;
static unsigned int mgag200_preferred_depth ( struct mga_device * mdev )
{
if ( IS_G200_SE ( mdev ) & & mdev - > vram_fb_available < ( 2048 * 1024 ) )
return 16 ;
else
return 32 ;
}
2012-04-17 15:01:25 +01:00
int mgag200_modeset_init ( struct mga_device * mdev )
{
2020-06-05 15:58:02 +02:00
struct drm_device * dev = & mdev - > base ;
2020-05-07 11:03:15 +02:00
struct drm_connector * connector = & mdev - > connector . base ;
2020-05-15 10:32:32 +02:00
struct drm_simple_display_pipe * pipe = & mdev - > display_pipe ;
size_t format_count = ARRAY_SIZE ( mgag200_simple_display_pipe_formats ) ;
2020-02-28 09:18:27 +01:00
int ret ;
2012-04-17 15:01:25 +01:00
2020-05-07 11:03:13 +02:00
mdev - > bpp_shifts [ 0 ] = 0 ;
mdev - > bpp_shifts [ 1 ] = 1 ;
mdev - > bpp_shifts [ 2 ] = 0 ;
mdev - > bpp_shifts [ 3 ] = 2 ;
2020-05-15 10:32:32 +02:00
mgag200_init_regs ( mdev ) ;
2020-05-07 11:03:13 +02:00
ret = drmm_mode_config_init ( dev ) ;
if ( ret ) {
drm_err ( dev , " drmm_mode_config_init() failed, error %d \n " ,
ret ) ;
return ret ;
}
2020-05-07 11:03:11 +02:00
dev - > mode_config . max_width = MGAG200_MAX_FB_WIDTH ;
dev - > mode_config . max_height = MGAG200_MAX_FB_HEIGHT ;
2012-04-17 15:01:25 +01:00
2020-05-07 11:03:13 +02:00
dev - > mode_config . preferred_depth = mgag200_preferred_depth ( mdev ) ;
2020-05-07 11:03:11 +02:00
dev - > mode_config . fb_base = mdev - > mc . vram_base ;
2012-04-17 15:01:25 +01:00
2020-05-07 11:03:13 +02:00
dev - > mode_config . funcs = & mgag200_mode_config_funcs ;
2020-05-15 10:32:32 +02:00
ret = mgag200_vga_connector_init ( mdev ) ;
2020-02-28 09:18:27 +01:00
if ( ret ) {
2020-05-07 11:03:11 +02:00
drm_err ( dev ,
2020-05-15 10:32:32 +02:00
" mgag200_vga_connector_init() failed, error %d \n " ,
2020-02-28 09:18:27 +01:00
ret ) ;
return ret ;
2012-04-17 15:01:25 +01:00
}
2020-05-15 10:32:32 +02:00
ret = drm_simple_display_pipe_init ( dev , pipe ,
& mgag200_simple_display_pipe_funcs ,
mgag200_simple_display_pipe_formats ,
format_count ,
mgag200_simple_display_pipe_fmtmods ,
connector ) ;
2020-05-07 11:03:15 +02:00
if ( ret ) {
drm_err ( dev ,
2020-05-15 10:32:32 +02:00
" drm_simple_display_pipe_init() failed, error %d \n " ,
2020-05-07 11:03:15 +02:00
ret ) ;
return ret ;
2012-04-17 15:01:25 +01:00
}
2020-05-15 10:32:32 +02:00
/* FIXME: legacy gamma tables; convert to CRTC state */
drm_mode_crtc_set_gamma_size ( & pipe - > crtc , MGAG200_LUT_SIZE ) ;
drm_mode_config_reset ( dev ) ;
2012-04-17 15:01:25 +01:00
return 0 ;
}