2010-04-17 19:44:53 +00:00
/*
* Copyright 1998 - 2008 VIA Technologies , Inc . All Rights Reserved .
* Copyright 2001 - 2008 S3 Graphics , Inc . All Rights Reserved .
* Copyright 2010 Florian Tobias Schandinat < FlorianSchandinat @ gmx . de >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation ;
* either version 2 , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTIES OR REPRESENTATIONS ; 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 . ,
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
/*
* basic modesetting functions
*/
# include <linux/kernel.h>
2010-05-05 14:44:55 -06:00
# include <linux/via-core.h>
2010-04-17 19:44:53 +00:00
# include "via_modesetting.h"
# include "share.h"
# include "debug.h"
2011-05-21 22:46:31 +00:00
void via_set_primary_timing ( const struct display_timing * timing )
{
struct display_timing raw ;
raw . hor_total = timing - > hor_total / 8 - 5 ;
raw . hor_addr = timing - > hor_addr / 8 - 1 ;
raw . hor_blank_start = timing - > hor_blank_start / 8 - 1 ;
raw . hor_blank_end = timing - > hor_blank_end / 8 - 1 ;
raw . hor_sync_start = timing - > hor_sync_start / 8 ;
raw . hor_sync_end = timing - > hor_sync_end / 8 ;
raw . ver_total = timing - > ver_total - 2 ;
raw . ver_addr = timing - > ver_addr - 1 ;
raw . ver_blank_start = timing - > ver_blank_start - 1 ;
raw . ver_blank_end = timing - > ver_blank_end - 1 ;
raw . ver_sync_start = timing - > ver_sync_start - 1 ;
raw . ver_sync_end = timing - > ver_sync_end - 1 ;
/* unlock timing registers */
via_write_reg_mask ( VIACR , 0x11 , 0x00 , 0x80 ) ;
via_write_reg ( VIACR , 0x00 , raw . hor_total & 0xFF ) ;
via_write_reg ( VIACR , 0x01 , raw . hor_addr & 0xFF ) ;
via_write_reg ( VIACR , 0x02 , raw . hor_blank_start & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x03 , raw . hor_blank_end & 0x1F , 0x1F ) ;
via_write_reg ( VIACR , 0x04 , raw . hor_sync_start & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x05 , ( raw . hor_sync_end & 0x1F )
| ( raw . hor_blank_end < < ( 7 - 5 ) & 0x80 ) , 0x9F ) ;
via_write_reg ( VIACR , 0x06 , raw . ver_total & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x07 , ( raw . ver_total > > 8 & 0x01 )
| ( raw . ver_addr > > ( 8 - 1 ) & 0x02 )
| ( raw . ver_sync_start > > ( 8 - 2 ) & 0x04 )
| ( raw . ver_blank_start > > ( 8 - 3 ) & 0x08 )
| ( raw . ver_total > > ( 9 - 5 ) & 0x20 )
| ( raw . ver_addr > > ( 9 - 6 ) & 0x40 )
| ( raw . ver_sync_start > > ( 9 - 7 ) & 0x80 ) , 0xEF ) ;
via_write_reg_mask ( VIACR , 0x09 , raw . ver_blank_start > > ( 9 - 5 ) & 0x20 ,
0x20 ) ;
via_write_reg ( VIACR , 0x10 , raw . ver_sync_start & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x11 , raw . ver_sync_end & 0x0F , 0x0F ) ;
via_write_reg ( VIACR , 0x12 , raw . ver_addr & 0xFF ) ;
via_write_reg ( VIACR , 0x15 , raw . ver_blank_start & 0xFF ) ;
via_write_reg ( VIACR , 0x16 , raw . ver_blank_end & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x33 , ( raw . hor_sync_start > > ( 8 - 4 ) & 0x10 )
| ( raw . hor_blank_end > > ( 6 - 5 ) & 0x20 ) , 0x30 ) ;
via_write_reg_mask ( VIACR , 0x35 , ( raw . ver_total > > 10 & 0x01 )
| ( raw . ver_sync_start > > ( 10 - 1 ) & 0x02 )
| ( raw . ver_addr > > ( 10 - 2 ) & 0x04 )
| ( raw . ver_blank_start > > ( 10 - 3 ) & 0x08 ) , 0x0F ) ;
via_write_reg_mask ( VIACR , 0x36 , raw . hor_total > > ( 8 - 3 ) & 0x08 , 0x08 ) ;
/* lock timing registers */
via_write_reg_mask ( VIACR , 0x11 , 0x80 , 0x80 ) ;
2011-05-22 23:40:46 +00:00
/* reset timing control */
via_write_reg_mask ( VIACR , 0x17 , 0x00 , 0x80 ) ;
via_write_reg_mask ( VIACR , 0x17 , 0x80 , 0x80 ) ;
2011-05-21 22:46:31 +00:00
}
void via_set_secondary_timing ( const struct display_timing * timing )
{
struct display_timing raw ;
raw . hor_total = timing - > hor_total - 1 ;
raw . hor_addr = timing - > hor_addr - 1 ;
raw . hor_blank_start = timing - > hor_blank_start - 1 ;
raw . hor_blank_end = timing - > hor_blank_end - 1 ;
raw . hor_sync_start = timing - > hor_sync_start - 1 ;
raw . hor_sync_end = timing - > hor_sync_end - 1 ;
raw . ver_total = timing - > ver_total - 1 ;
raw . ver_addr = timing - > ver_addr - 1 ;
raw . ver_blank_start = timing - > ver_blank_start - 1 ;
raw . ver_blank_end = timing - > ver_blank_end - 1 ;
raw . ver_sync_start = timing - > ver_sync_start - 1 ;
raw . ver_sync_end = timing - > ver_sync_end - 1 ;
via_write_reg ( VIACR , 0x50 , raw . hor_total & 0xFF ) ;
via_write_reg ( VIACR , 0x51 , raw . hor_addr & 0xFF ) ;
via_write_reg ( VIACR , 0x52 , raw . hor_blank_start & 0xFF ) ;
via_write_reg ( VIACR , 0x53 , raw . hor_blank_end & 0xFF ) ;
via_write_reg ( VIACR , 0x54 , ( raw . hor_blank_start > > 8 & 0x07 )
| ( raw . hor_blank_end > > ( 8 - 3 ) & 0x38 )
| ( raw . hor_sync_start > > ( 8 - 6 ) & 0xC0 ) ) ;
via_write_reg_mask ( VIACR , 0x55 , ( raw . hor_total > > 8 & 0x0F )
| ( raw . hor_addr > > ( 8 - 4 ) & 0x70 ) , 0x7F ) ;
via_write_reg ( VIACR , 0x56 , raw . hor_sync_start & 0xFF ) ;
via_write_reg ( VIACR , 0x57 , raw . hor_sync_end & 0xFF ) ;
via_write_reg ( VIACR , 0x58 , raw . ver_total & 0xFF ) ;
via_write_reg ( VIACR , 0x59 , raw . ver_addr & 0xFF ) ;
via_write_reg ( VIACR , 0x5A , raw . ver_blank_start & 0xFF ) ;
via_write_reg ( VIACR , 0x5B , raw . ver_blank_end & 0xFF ) ;
via_write_reg ( VIACR , 0x5C , ( raw . ver_blank_start > > 8 & 0x07 )
| ( raw . ver_blank_end > > ( 8 - 3 ) & 0x38 )
| ( raw . hor_sync_end > > ( 8 - 6 ) & 0x40 )
| ( raw . hor_sync_start > > ( 10 - 7 ) & 0x80 ) ) ;
via_write_reg ( VIACR , 0x5D , ( raw . ver_total > > 8 & 0x07 )
| ( raw . ver_addr > > ( 8 - 3 ) & 0x38 )
| ( raw . hor_blank_end > > ( 11 - 6 ) & 0x40 )
| ( raw . hor_sync_start > > ( 11 - 7 ) & 0x80 ) ) ;
via_write_reg ( VIACR , 0x5E , raw . ver_sync_start & 0xFF ) ;
via_write_reg ( VIACR , 0x5F , ( raw . ver_sync_end & 0x1F )
| ( raw . ver_sync_start > > ( 8 - 5 ) & 0xE0 ) ) ;
}
2010-04-17 19:44:53 +00:00
void via_set_primary_address ( u32 addr )
{
DEBUG_MSG ( KERN_DEBUG " via_set_primary_address(0x%08X) \n " , addr ) ;
via_write_reg ( VIACR , 0x0D , addr & 0xFF ) ;
via_write_reg ( VIACR , 0x0C , ( addr > > 8 ) & 0xFF ) ;
via_write_reg ( VIACR , 0x34 , ( addr > > 16 ) & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x48 , ( addr > > 24 ) & 0x1F , 0x1F ) ;
}
void via_set_secondary_address ( u32 addr )
{
DEBUG_MSG ( KERN_DEBUG " via_set_secondary_address(0x%08X) \n " , addr ) ;
/* secondary display supports only quadword aligned memory */
via_write_reg_mask ( VIACR , 0x62 , ( addr > > 2 ) & 0xFE , 0xFE ) ;
via_write_reg ( VIACR , 0x63 , ( addr > > 10 ) & 0xFF ) ;
via_write_reg ( VIACR , 0x64 , ( addr > > 18 ) & 0xFF ) ;
via_write_reg_mask ( VIACR , 0xA3 , ( addr > > 26 ) & 0x07 , 0x07 ) ;
}
void via_set_primary_pitch ( u32 pitch )
{
DEBUG_MSG ( KERN_DEBUG " via_set_primary_pitch(0x%08X) \n " , pitch ) ;
/* spec does not say that first adapter skips 3 bits but old
* code did it and seems to be reasonable in analogy to 2 nd adapter
*/
pitch = pitch > > 3 ;
via_write_reg ( VIACR , 0x13 , pitch & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x35 , ( pitch > > ( 8 - 5 ) ) & 0xE0 , 0xE0 ) ;
}
void via_set_secondary_pitch ( u32 pitch )
{
DEBUG_MSG ( KERN_DEBUG " via_set_secondary_pitch(0x%08X) \n " , pitch ) ;
pitch = pitch > > 3 ;
via_write_reg ( VIACR , 0x66 , pitch & 0xFF ) ;
via_write_reg_mask ( VIACR , 0x67 , ( pitch > > 8 ) & 0x03 , 0x03 ) ;
via_write_reg_mask ( VIACR , 0x71 , ( pitch > > ( 10 - 7 ) ) & 0x80 , 0x80 ) ;
}
void via_set_primary_color_depth ( u8 depth )
{
u8 value ;
DEBUG_MSG ( KERN_DEBUG " via_set_primary_color_depth(%d) \n " , depth ) ;
switch ( depth ) {
case 8 :
value = 0x00 ;
break ;
case 15 :
value = 0x04 ;
break ;
case 16 :
value = 0x14 ;
break ;
case 24 :
value = 0x0C ;
break ;
case 30 :
value = 0x08 ;
break ;
default :
printk ( KERN_WARNING " via_set_primary_color_depth: "
" Unsupported depth: %d \n " , depth ) ;
return ;
}
via_write_reg_mask ( VIASR , 0x15 , value , 0x1C ) ;
}
void via_set_secondary_color_depth ( u8 depth )
{
u8 value ;
DEBUG_MSG ( KERN_DEBUG " via_set_secondary_color_depth(%d) \n " , depth ) ;
switch ( depth ) {
case 8 :
value = 0x00 ;
break ;
case 16 :
value = 0x40 ;
break ;
case 24 :
value = 0xC0 ;
break ;
case 30 :
value = 0x80 ;
break ;
default :
printk ( KERN_WARNING " via_set_secondary_color_depth: "
" Unsupported depth: %d \n " , depth ) ;
return ;
}
via_write_reg_mask ( VIACR , 0x67 , value , 0xC0 ) ;
}