2005-04-16 15:20:36 -07:00
/*
* drivers / video / aty / radeon_base . c
*
* framebuffer driver for ATI Radeon chipset video boards
*
* Copyright 2003 Ben . Herrenschmidt < benh @ kernel . crashing . org >
* Copyright 2000 Ani Joshi < ajoshi @ kernel . crashing . org >
*
* i2c bits from Luca Tettamanti < kronos @ kronoz . cjb . net >
*
* Special thanks to ATI DevRel team for their hardware donations .
*
* . . . Insert GPL boilerplate here . . .
*
* Significant portions of this driver apdated from XFree86 Radeon
* driver which has the following copyright notice :
*
* Copyright 2000 ATI Technologies Inc . , Markham , Ontario , and
* VA Linux Systems Inc . , Fremont , California .
*
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining
* a copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation on the rights to use , copy , modify , merge ,
* publish , distribute , sublicense , and / or sell copies of the Software ,
* and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial
* portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NON - INFRINGEMENT . IN NO EVENT SHALL ATI , VA LINUX SYSTEMS AND / OR
* THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
*
* XFree86 driver authors :
*
* Kevin E . Martin < martin @ xfree86 . org >
* Rickard E . Faith < faith @ valinux . com >
* Alan Hourihane < alanh @ fairlite . demon . co . uk >
*
*/
# define RADEON_VERSION "0.2.0"
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/time.h>
# include <linux/fb.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/vmalloc.h>
# include <linux/device.h>
# include <asm/io.h>
# include <asm/uaccess.h>
# ifdef CONFIG_PPC_OF
# include <asm/pci-bridge.h>
# include "../macmodes.h"
# ifdef CONFIG_BOOTX_TEXT
# include <asm/btext.h>
# endif
# endif /* CONFIG_PPC_OF */
# ifdef CONFIG_MTRR
# include <asm/mtrr.h>
# endif
# include <video/radeon.h>
# include <linux/radeonfb.h>
# include "../edid.h" // MOVE THAT TO include/video
# include "ati_ids.h"
# include "radeonfb.h"
# define MAX_MAPPED_VRAM (2048*2048*4)
# define MIN_MAPPED_VRAM (1024*768*1)
# define CHIP_DEF(id, family, flags) \
{ PCI_VENDOR_ID_ATI , id , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , ( flags ) | ( CHIP_FAMILY_ # # family ) }
static struct pci_device_id radeonfb_pci_table [ ] = {
2007-05-08 00:37:59 -07:00
/* Radeon Xpress 200m */
CHIP_DEF ( PCI_CHIP_RS480_5955 , RS480 , CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY ) ,
2005-04-16 15:20:36 -07:00
/* Mobility M6 */
CHIP_DEF ( PCI_CHIP_RADEON_LY , RV100 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RADEON_LZ , RV100 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
/* Radeon VE/7000 */
CHIP_DEF ( PCI_CHIP_RV100_QY , RV100 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV100_QZ , RV100 , CHIP_HAS_CRTC2 ) ,
2005-11-07 01:00:55 -08:00
CHIP_DEF ( PCI_CHIP_RN50 , RV100 , CHIP_HAS_CRTC2 ) ,
2005-04-16 15:20:36 -07:00
/* Radeon IGP320M (U1) */
CHIP_DEF ( PCI_CHIP_RS100_4336 , RS100 , CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY ) ,
/* Radeon IGP320 (A3) */
CHIP_DEF ( PCI_CHIP_RS100_4136 , RS100 , CHIP_HAS_CRTC2 | CHIP_IS_IGP ) ,
/* IGP330M/340M/350M (U2) */
CHIP_DEF ( PCI_CHIP_RS200_4337 , RS200 , CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY ) ,
/* IGP330/340/350 (A4) */
CHIP_DEF ( PCI_CHIP_RS200_4137 , RS200 , CHIP_HAS_CRTC2 | CHIP_IS_IGP ) ,
/* Mobility 7000 IGP */
CHIP_DEF ( PCI_CHIP_RS250_4437 , RS200 , CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY ) ,
/* 7000 IGP (A4+) */
CHIP_DEF ( PCI_CHIP_RS250_4237 , RS200 , CHIP_HAS_CRTC2 | CHIP_IS_IGP ) ,
/* 8500 AIW */
CHIP_DEF ( PCI_CHIP_R200_BB , R200 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R200_BC , R200 , CHIP_HAS_CRTC2 ) ,
/* 8700/8800 */
CHIP_DEF ( PCI_CHIP_R200_QH , R200 , CHIP_HAS_CRTC2 ) ,
/* 8500 */
CHIP_DEF ( PCI_CHIP_R200_QL , R200 , CHIP_HAS_CRTC2 ) ,
/* 9100 */
CHIP_DEF ( PCI_CHIP_R200_QM , R200 , CHIP_HAS_CRTC2 ) ,
/* Mobility M7 */
CHIP_DEF ( PCI_CHIP_RADEON_LW , RV200 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RADEON_LX , RV200 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
/* 7500 */
CHIP_DEF ( PCI_CHIP_RV200_QW , RV200 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV200_QX , RV200 , CHIP_HAS_CRTC2 ) ,
/* Mobility M9 */
CHIP_DEF ( PCI_CHIP_RV250_Ld , RV250 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV250_Le , RV250 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV250_Lf , RV250 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV250_Lg , RV250 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
/* 9000/Pro */
CHIP_DEF ( PCI_CHIP_RV250_If , RV250 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV250_Ig , RV250 , CHIP_HAS_CRTC2 ) ,
/* Mobility 9100 IGP (U3) */
CHIP_DEF ( PCI_CHIP_RS300_5835 , RS300 , CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RS350_7835 , RS300 , CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY ) ,
/* 9100 IGP (A5) */
CHIP_DEF ( PCI_CHIP_RS300_5834 , RS300 , CHIP_HAS_CRTC2 | CHIP_IS_IGP ) ,
CHIP_DEF ( PCI_CHIP_RS350_7834 , RS300 , CHIP_HAS_CRTC2 | CHIP_IS_IGP ) ,
/* Mobility 9200 (M9+) */
CHIP_DEF ( PCI_CHIP_RV280_5C61 , RV280 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV280_5C63 , RV280 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
/* 9200 */
CHIP_DEF ( PCI_CHIP_RV280_5960 , RV280 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV280_5961 , RV280 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV280_5962 , RV280 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV280_5964 , RV280 , CHIP_HAS_CRTC2 ) ,
/* 9500 */
CHIP_DEF ( PCI_CHIP_R300_AD , R300 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R300_AE , R300 , CHIP_HAS_CRTC2 ) ,
/* 9600TX / FireGL Z1 */
CHIP_DEF ( PCI_CHIP_R300_AF , R300 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R300_AG , R300 , CHIP_HAS_CRTC2 ) ,
/* 9700/9500/Pro/FireGL X1 */
CHIP_DEF ( PCI_CHIP_R300_ND , R300 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R300_NE , R300 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R300_NF , R300 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R300_NG , R300 , CHIP_HAS_CRTC2 ) ,
/* Mobility M10/M11 */
CHIP_DEF ( PCI_CHIP_RV350_NP , RV350 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV350_NQ , RV350 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV350_NR , RV350 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV350_NS , RV350 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV350_NT , RV350 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV350_NV , RV350 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
/* 9600/FireGL T2 */
CHIP_DEF ( PCI_CHIP_RV350_AP , RV350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV350_AQ , RV350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV360_AR , RV350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV350_AS , RV350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV350_AT , RV350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV350_AV , RV350 , CHIP_HAS_CRTC2 ) ,
/* 9800/Pro/FileGL X2 */
CHIP_DEF ( PCI_CHIP_R350_AH , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R350_AI , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R350_AJ , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R350_AK , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R350_NH , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R350_NI , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R360_NJ , R350 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R350_NK , R350 , CHIP_HAS_CRTC2 ) ,
/* Newer stuff */
CHIP_DEF ( PCI_CHIP_RV380_3E50 , RV380 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV380_3E54 , RV380 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV380_3150 , RV380 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV380_3154 , RV380 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV370_5B60 , RV380 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV370_5B62 , RV380 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV370_5B64 , RV380 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV370_5B65 , RV380 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_RV370_5460 , RV380 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_RV370_5464 , RV380 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_R420_JH , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R420_JI , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R420_JJ , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R420_JK , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R420_JL , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R420_JM , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R420_JN , R420 , CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY ) ,
CHIP_DEF ( PCI_CHIP_R420_JP , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UH , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UI , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UJ , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UK , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UQ , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UR , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_UT , R420 , CHIP_HAS_CRTC2 ) ,
CHIP_DEF ( PCI_CHIP_R423_5D57 , R420 , CHIP_HAS_CRTC2 ) ,
/* Original Radeon/7200 */
CHIP_DEF ( PCI_CHIP_RADEON_QD , RADEON , 0 ) ,
CHIP_DEF ( PCI_CHIP_RADEON_QE , RADEON , 0 ) ,
CHIP_DEF ( PCI_CHIP_RADEON_QF , RADEON , 0 ) ,
CHIP_DEF ( PCI_CHIP_RADEON_QG , RADEON , 0 ) ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , radeonfb_pci_table ) ;
typedef struct {
u16 reg ;
u32 val ;
} reg_val ;
/* these common regs are cleared before mode setting so they do not
* interfere with anything
*/
static reg_val common_regs [ ] = {
{ OVR_CLR , 0 } ,
{ OVR_WID_LEFT_RIGHT , 0 } ,
{ OVR_WID_TOP_BOTTOM , 0 } ,
{ OV0_SCALE_CNTL , 0 } ,
{ SUBPIC_CNTL , 0 } ,
{ VIPH_CONTROL , 0 } ,
{ I2C_CNTL_1 , 0 } ,
{ GEN_INT_CNTL , 0 } ,
{ CAP0_TRIG_CNTL , 0 } ,
{ CAP1_TRIG_CNTL , 0 } ,
} ;
/*
* globals
*/
static char * mode_option ;
static char * monitor_layout ;
static int noaccel = 0 ;
static int default_dynclk = - 2 ;
static int nomodeset = 0 ;
static int ignore_edid = 0 ;
static int mirror = 0 ;
static int panel_yres = 0 ;
static int force_dfp = 0 ;
static int force_measure_pll = 0 ;
# ifdef CONFIG_MTRR
static int nomtrr = 0 ;
# endif
2006-07-30 03:04:18 -07:00
static int force_sleep ;
static int ignore_devlist ;
2007-03-03 17:43:52 +00:00
# ifdef CONFIG_PMAC_BACKLIGHT
static int backlight = 1 ;
# else
static int backlight = 0 ;
# endif
2005-04-16 15:20:36 -07:00
/*
* prototypes
*/
static void radeon_unmap_ROM ( struct radeonfb_info * rinfo , struct pci_dev * dev )
{
if ( ! rinfo - > bios_seg )
return ;
pci_unmap_rom ( dev , rinfo - > bios_seg ) ;
}
static int __devinit radeon_map_ROM ( struct radeonfb_info * rinfo , struct pci_dev * dev )
{
void __iomem * rom ;
u16 dptr ;
u8 rom_type ;
size_t rom_size ;
/* If this is a primary card, there is a shadow copy of the
* ROM somewhere in the first meg . We will just ignore the copy
* and use the ROM directly .
*/
/* Fix from ATI for problem with Radeon hardware not leaving ROM enabled */
unsigned int temp ;
temp = INREG ( MPP_TB_CONFIG ) ;
temp & = 0x00ffffffu ;
temp | = 0x04 < < 24 ;
OUTREG ( MPP_TB_CONFIG , temp ) ;
temp = INREG ( MPP_TB_CONFIG ) ;
rom = pci_map_rom ( dev , & rom_size ) ;
if ( ! rom ) {
printk ( KERN_ERR " radeonfb (%s): ROM failed to map \n " ,
pci_name ( rinfo - > pdev ) ) ;
return - ENOMEM ;
}
rinfo - > bios_seg = rom ;
/* Very simple test to make sure it appeared */
if ( BIOS_IN16 ( 0 ) ! = 0xaa55 ) {
2005-09-09 13:10:06 -07:00
printk ( KERN_DEBUG " radeonfb (%s): Invalid ROM signature %x "
" should be 0xaa55 \n " ,
pci_name ( rinfo - > pdev ) , BIOS_IN16 ( 0 ) ) ;
2005-04-16 15:20:36 -07:00
goto failed ;
}
/* Look for the PCI data to check the ROM type */
dptr = BIOS_IN16 ( 0x18 ) ;
/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
* for now , until I ' ve verified this works everywhere . The goal here is more
* to phase out Open Firmware images .
*
* Currently , we only look at the first PCI data , we could iteratre and deal with
* them all , and we should use fb_bios_start relative to start of image and not
* relative start of ROM , but so far , I never found a dual - image ATI card
*
* typedef struct {
* u32 signature ; + 0x00
* u16 vendor ; + 0x04
* u16 device ; + 0x06
* u16 reserved_1 ; + 0x08
* u16 dlen ; + 0x0a
* u8 drevision ; + 0x0c
* u8 class_hi ; + 0x0d
* u16 class_lo ; + 0x0e
* u16 ilen ; + 0x10
* u16 irevision ; + 0x12
* u8 type ; + 0x14
* u8 indicator ; + 0x15
* u16 reserved_2 ; + 0x16
* } pci_data_t ;
*/
if ( BIOS_IN32 ( dptr ) ! = ( ( ' R ' < < 24 ) | ( ' I ' < < 16 ) | ( ' C ' < < 8 ) | ' P ' ) ) {
printk ( KERN_WARNING " radeonfb (%s): PCI DATA signature in ROM "
" incorrect: %08x \n " , pci_name ( rinfo - > pdev ) , BIOS_IN32 ( dptr ) ) ;
goto anyway ;
}
rom_type = BIOS_IN8 ( dptr + 0x14 ) ;
switch ( rom_type ) {
case 0 :
printk ( KERN_INFO " radeonfb: Found Intel x86 BIOS ROM Image \n " ) ;
break ;
case 1 :
printk ( KERN_INFO " radeonfb: Found Open Firmware ROM Image \n " ) ;
goto failed ;
case 2 :
printk ( KERN_INFO " radeonfb: Found HP PA-RISC ROM Image \n " ) ;
goto failed ;
default :
printk ( KERN_INFO " radeonfb: Found unknown type %d ROM Image \n " , rom_type ) ;
goto failed ;
}
anyway :
/* Locate the flat panel infos, do some sanity checking !!! */
rinfo - > fp_bios_start = BIOS_IN16 ( 0x48 ) ;
return 0 ;
failed :
rinfo - > bios_seg = NULL ;
radeon_unmap_ROM ( rinfo , dev ) ;
return - ENXIO ;
}
# ifdef CONFIG_X86
static int __devinit radeon_find_mem_vbios ( struct radeonfb_info * rinfo )
{
/* I simplified this code as we used to miss the signatures in
* a lot of case . It ' s now closer to XFree , we just don ' t check
* for signatures at all . . . Something better will have to be done
* if we end up having conflicts
*/
u32 segstart ;
void __iomem * rom_base = NULL ;
for ( segstart = 0x000c0000 ; segstart < 0x000f0000 ; segstart + = 0x00001000 ) {
rom_base = ioremap ( segstart , 0x10000 ) ;
if ( rom_base = = NULL )
return - ENOMEM ;
if ( readb ( rom_base ) = = 0x55 & & readb ( rom_base + 1 ) = = 0xaa )
break ;
iounmap ( rom_base ) ;
rom_base = NULL ;
}
if ( rom_base = = NULL )
return - ENXIO ;
/* Locate the flat panel infos, do some sanity checking !!! */
rinfo - > bios_seg = rom_base ;
rinfo - > fp_bios_start = BIOS_IN16 ( 0x48 ) ;
return 0 ;
}
# endif
2007-03-29 01:33:46 -07:00
# if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
2005-04-16 15:20:36 -07:00
/*
* Read XTAL ( ref clock ) , SCLK and MCLK from Open Firmware device
* tree . Hopefully , ATI OF driver is kind enough to fill these
*/
static int __devinit radeon_read_xtal_OF ( struct radeonfb_info * rinfo )
{
struct device_node * dp = rinfo - > of_node ;
2006-07-12 15:40:40 +10:00
const u32 * val ;
2005-04-16 15:20:36 -07:00
if ( dp = = NULL )
return - ENODEV ;
2007-05-01 13:54:02 +10:00
val = of_get_property ( dp , " ATY,RefCLK " , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( ! val | | ! * val ) {
printk ( KERN_WARNING " radeonfb: No ATY,RefCLK property ! \n " ) ;
return - EINVAL ;
}
rinfo - > pll . ref_clk = ( * val ) / 10 ;
2007-05-01 13:54:02 +10:00
val = of_get_property ( dp , " ATY,SCLK " , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( val & & * val )
rinfo - > pll . sclk = ( * val ) / 10 ;
2007-05-01 13:54:02 +10:00
val = of_get_property ( dp , " ATY,MCLK " , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( val & & * val )
rinfo - > pll . mclk = ( * val ) / 10 ;
return 0 ;
}
2007-03-29 01:33:46 -07:00
# endif /* CONFIG_PPC_OF || CONFIG_SPARC */
2005-04-16 15:20:36 -07:00
/*
* Read PLL infos from chip registers
*/
static int __devinit radeon_probe_pll_params ( struct radeonfb_info * rinfo )
{
unsigned char ppll_div_sel ;
unsigned Ns , Nm , M ;
unsigned sclk , mclk , tmp , ref_div ;
int hTotal , vTotal , num , denom , m , n ;
unsigned long long hz , vclk ;
long xtal ;
struct timeval start_tv , stop_tv ;
long total_secs , total_usecs ;
int i ;
/* Ugh, we cut interrupts, bad bad bad, but we want some precision
* here , so . . . - - BenH
*/
/* Flush PCI buffers ? */
2005-09-29 19:26:51 -07:00
tmp = INREG16 ( DEVICE_ID ) ;
2005-04-16 15:20:36 -07:00
local_irq_disable ( ) ;
for ( i = 0 ; i < 1000000 ; i + + )
if ( ( ( INREG ( CRTC_VLINE_CRNT_VLINE ) > > 16 ) & 0x3ff ) = = 0 )
break ;
do_gettimeofday ( & start_tv ) ;
for ( i = 0 ; i < 1000000 ; i + + )
if ( ( ( INREG ( CRTC_VLINE_CRNT_VLINE ) > > 16 ) & 0x3ff ) ! = 0 )
break ;
for ( i = 0 ; i < 1000000 ; i + + )
if ( ( ( INREG ( CRTC_VLINE_CRNT_VLINE ) > > 16 ) & 0x3ff ) = = 0 )
break ;
do_gettimeofday ( & stop_tv ) ;
local_irq_enable ( ) ;
total_secs = stop_tv . tv_sec - start_tv . tv_sec ;
if ( total_secs > 10 )
return - 1 ;
total_usecs = stop_tv . tv_usec - start_tv . tv_usec ;
total_usecs + = total_secs * 1000000 ;
if ( total_usecs < 0 )
total_usecs = - total_usecs ;
hz = 1000000 / total_usecs ;
hTotal = ( ( INREG ( CRTC_H_TOTAL_DISP ) & 0x1ff ) + 1 ) * 8 ;
vTotal = ( ( INREG ( CRTC_V_TOTAL_DISP ) & 0x3ff ) + 1 ) ;
vclk = ( long long ) hTotal * ( long long ) vTotal * hz ;
switch ( ( INPLL ( PPLL_REF_DIV ) & 0x30000 ) > > 16 ) {
case 0 :
default :
num = 1 ;
denom = 1 ;
break ;
case 1 :
n = ( ( INPLL ( M_SPLL_REF_FB_DIV ) > > 16 ) & 0xff ) ;
m = ( INPLL ( M_SPLL_REF_FB_DIV ) & 0xff ) ;
num = 2 * n ;
denom = 2 * m ;
break ;
case 2 :
n = ( ( INPLL ( M_SPLL_REF_FB_DIV ) > > 8 ) & 0xff ) ;
m = ( INPLL ( M_SPLL_REF_FB_DIV ) & 0xff ) ;
num = 2 * n ;
denom = 2 * m ;
break ;
}
ppll_div_sel = INREG8 ( CLOCK_CNTL_INDEX + 1 ) & 0x3 ;
radeon_pll_errata_after_index ( rinfo ) ;
n = ( INPLL ( PPLL_DIV_0 + ppll_div_sel ) & 0x7ff ) ;
m = ( INPLL ( PPLL_REF_DIV ) & 0x3ff ) ;
num * = n ;
denom * = m ;
switch ( ( INPLL ( PPLL_DIV_0 + ppll_div_sel ) > > 16 ) & 0x7 ) {
case 1 :
denom * = 2 ;
break ;
case 2 :
denom * = 4 ;
break ;
case 3 :
denom * = 8 ;
break ;
case 4 :
denom * = 3 ;
break ;
case 6 :
denom * = 6 ;
break ;
case 7 :
denom * = 12 ;
break ;
}
vclk * = denom ;
do_div ( vclk , 1000 * num ) ;
xtal = vclk ;
if ( ( xtal > 26900 ) & & ( xtal < 27100 ) )
xtal = 2700 ;
else if ( ( xtal > 14200 ) & & ( xtal < 14400 ) )
xtal = 1432 ;
else if ( ( xtal > 29400 ) & & ( xtal < 29600 ) )
xtal = 2950 ;
else {
printk ( KERN_WARNING " xtal calculation failed: %ld \n " , xtal ) ;
return - 1 ;
}
tmp = INPLL ( M_SPLL_REF_FB_DIV ) ;
ref_div = INPLL ( PPLL_REF_DIV ) & 0x3ff ;
Ns = ( tmp & 0xff0000 ) > > 16 ;
Nm = ( tmp & 0xff00 ) > > 8 ;
M = ( tmp & 0xff ) ;
sclk = round_div ( ( 2 * Ns * xtal ) , ( 2 * M ) ) ;
mclk = round_div ( ( 2 * Nm * xtal ) , ( 2 * M ) ) ;
/* we're done, hopefully these are sane values */
rinfo - > pll . ref_clk = xtal ;
rinfo - > pll . ref_div = ref_div ;
rinfo - > pll . sclk = sclk ;
rinfo - > pll . mclk = mclk ;
return 0 ;
}
/*
2006-01-03 13:27:11 +01:00
* Retrieve PLL infos by different means ( BIOS , Open Firmware , register probing . . . )
2005-04-16 15:20:36 -07:00
*/
static void __devinit radeon_get_pllinfo ( struct radeonfb_info * rinfo )
{
/*
* In the case nothing works , these are defaults ; they are mostly
* incomplete , however . It does provide ppll_max and _min values
* even for most other methods , however .
*/
switch ( rinfo - > chipset ) {
case PCI_DEVICE_ID_ATI_RADEON_QW :
case PCI_DEVICE_ID_ATI_RADEON_QX :
rinfo - > pll . ppll_max = 35000 ;
rinfo - > pll . ppll_min = 12000 ;
rinfo - > pll . mclk = 23000 ;
rinfo - > pll . sclk = 23000 ;
rinfo - > pll . ref_clk = 2700 ;
break ;
case PCI_DEVICE_ID_ATI_RADEON_QL :
case PCI_DEVICE_ID_ATI_RADEON_QN :
case PCI_DEVICE_ID_ATI_RADEON_QO :
case PCI_DEVICE_ID_ATI_RADEON_Ql :
case PCI_DEVICE_ID_ATI_RADEON_BB :
rinfo - > pll . ppll_max = 35000 ;
rinfo - > pll . ppll_min = 12000 ;
rinfo - > pll . mclk = 27500 ;
rinfo - > pll . sclk = 27500 ;
rinfo - > pll . ref_clk = 2700 ;
break ;
case PCI_DEVICE_ID_ATI_RADEON_Id :
case PCI_DEVICE_ID_ATI_RADEON_Ie :
case PCI_DEVICE_ID_ATI_RADEON_If :
case PCI_DEVICE_ID_ATI_RADEON_Ig :
rinfo - > pll . ppll_max = 35000 ;
rinfo - > pll . ppll_min = 12000 ;
rinfo - > pll . mclk = 25000 ;
rinfo - > pll . sclk = 25000 ;
rinfo - > pll . ref_clk = 2700 ;
break ;
case PCI_DEVICE_ID_ATI_RADEON_ND :
case PCI_DEVICE_ID_ATI_RADEON_NE :
case PCI_DEVICE_ID_ATI_RADEON_NF :
case PCI_DEVICE_ID_ATI_RADEON_NG :
rinfo - > pll . ppll_max = 40000 ;
rinfo - > pll . ppll_min = 20000 ;
rinfo - > pll . mclk = 27000 ;
rinfo - > pll . sclk = 27000 ;
rinfo - > pll . ref_clk = 2700 ;
break ;
case PCI_DEVICE_ID_ATI_RADEON_QD :
case PCI_DEVICE_ID_ATI_RADEON_QE :
case PCI_DEVICE_ID_ATI_RADEON_QF :
case PCI_DEVICE_ID_ATI_RADEON_QG :
default :
rinfo - > pll . ppll_max = 35000 ;
rinfo - > pll . ppll_min = 12000 ;
rinfo - > pll . mclk = 16600 ;
rinfo - > pll . sclk = 16600 ;
rinfo - > pll . ref_clk = 2700 ;
break ;
}
rinfo - > pll . ref_div = INPLL ( PPLL_REF_DIV ) & PPLL_REF_DIV_MASK ;
2007-03-29 01:33:46 -07:00
# if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
2005-04-16 15:20:36 -07:00
/*
2006-01-03 13:27:11 +01:00
* Retrieve PLL infos from Open Firmware first
2005-04-16 15:20:36 -07:00
*/
if ( ! force_measure_pll & & radeon_read_xtal_OF ( rinfo ) = = 0 ) {
2006-01-03 13:27:11 +01:00
printk ( KERN_INFO " radeonfb: Retrieved PLL infos from Open Firmware \n " ) ;
2005-04-16 15:20:36 -07:00
goto found ;
}
2007-03-29 01:33:46 -07:00
# endif /* CONFIG_PPC_OF || CONFIG_SPARC */
2005-04-16 15:20:36 -07:00
/*
* Check out if we have an X86 which gave us some PLL informations
2006-01-03 13:27:11 +01:00
* and if yes , retrieve them
2005-04-16 15:20:36 -07:00
*/
if ( ! force_measure_pll & & rinfo - > bios_seg ) {
u16 pll_info_block = BIOS_IN16 ( rinfo - > fp_bios_start + 0x30 ) ;
rinfo - > pll . sclk = BIOS_IN16 ( pll_info_block + 0x08 ) ;
rinfo - > pll . mclk = BIOS_IN16 ( pll_info_block + 0x0a ) ;
rinfo - > pll . ref_clk = BIOS_IN16 ( pll_info_block + 0x0e ) ;
rinfo - > pll . ref_div = BIOS_IN16 ( pll_info_block + 0x10 ) ;
rinfo - > pll . ppll_min = BIOS_IN32 ( pll_info_block + 0x12 ) ;
rinfo - > pll . ppll_max = BIOS_IN32 ( pll_info_block + 0x16 ) ;
2006-01-03 13:27:11 +01:00
printk ( KERN_INFO " radeonfb: Retrieved PLL infos from BIOS \n " ) ;
2005-04-16 15:20:36 -07:00
goto found ;
}
/*
* We didn ' t get PLL parameters from either OF or BIOS , we try to
* probe them
*/
if ( radeon_probe_pll_params ( rinfo ) = = 0 ) {
2006-01-03 13:27:11 +01:00
printk ( KERN_INFO " radeonfb: Retrieved PLL infos from registers \n " ) ;
2005-04-16 15:20:36 -07:00
goto found ;
}
/*
* Fall back to already - set defaults . . .
*/
printk ( KERN_INFO " radeonfb: Used default PLL infos \n " ) ;
found :
/*
2006-01-03 13:27:11 +01:00
* Some methods fail to retrieve SCLK and MCLK values , we apply default
2005-04-16 15:20:36 -07:00
* settings in this case ( 200 Mhz ) . If that really happne often , we could
* fetch from registers instead . . .
*/
if ( rinfo - > pll . mclk = = 0 )
rinfo - > pll . mclk = 20000 ;
if ( rinfo - > pll . sclk = = 0 )
rinfo - > pll . sclk = 20000 ;
printk ( " radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz \n " ,
rinfo - > pll . ref_clk / 100 , rinfo - > pll . ref_clk % 100 ,
rinfo - > pll . ref_div ,
rinfo - > pll . mclk / 100 , rinfo - > pll . mclk % 100 ,
rinfo - > pll . sclk / 100 , rinfo - > pll . sclk % 100 ) ;
printk ( " radeonfb: PLL min %d max %d \n " , rinfo - > pll . ppll_min , rinfo - > pll . ppll_max ) ;
}
static int radeonfb_check_var ( struct fb_var_screeninfo * var , struct fb_info * info )
{
struct radeonfb_info * rinfo = info - > par ;
struct fb_var_screeninfo v ;
int nom , den ;
unsigned int pitch ;
if ( radeon_match_mode ( rinfo , & v , var ) )
return - EINVAL ;
switch ( v . bits_per_pixel ) {
case 0 . . . 8 :
v . bits_per_pixel = 8 ;
break ;
case 9 . . . 16 :
v . bits_per_pixel = 16 ;
break ;
case 17 . . . 24 :
#if 0 /* Doesn't seem to work */
v . bits_per_pixel = 24 ;
break ;
# endif
return - EINVAL ;
case 25 . . . 32 :
v . bits_per_pixel = 32 ;
break ;
default :
return - EINVAL ;
}
switch ( var_to_depth ( & v ) ) {
case 8 :
nom = den = 1 ;
v . red . offset = v . green . offset = v . blue . offset = 0 ;
v . red . length = v . green . length = v . blue . length = 8 ;
v . transp . offset = v . transp . length = 0 ;
break ;
case 15 :
nom = 2 ;
den = 1 ;
v . red . offset = 10 ;
v . green . offset = 5 ;
v . blue . offset = 0 ;
v . red . length = v . green . length = v . blue . length = 5 ;
v . transp . offset = v . transp . length = 0 ;
break ;
case 16 :
nom = 2 ;
den = 1 ;
v . red . offset = 11 ;
v . green . offset = 5 ;
v . blue . offset = 0 ;
v . red . length = 5 ;
v . green . length = 6 ;
v . blue . length = 5 ;
v . transp . offset = v . transp . length = 0 ;
break ;
case 24 :
nom = 4 ;
den = 1 ;
v . red . offset = 16 ;
v . green . offset = 8 ;
v . blue . offset = 0 ;
v . red . length = v . blue . length = v . green . length = 8 ;
v . transp . offset = v . transp . length = 0 ;
break ;
case 32 :
nom = 4 ;
den = 1 ;
v . red . offset = 16 ;
v . green . offset = 8 ;
v . blue . offset = 0 ;
v . red . length = v . blue . length = v . green . length = 8 ;
v . transp . offset = 24 ;
v . transp . length = 8 ;
break ;
default :
printk ( " radeonfb: mode %dx%dx%d rejected, color depth invalid \n " ,
var - > xres , var - > yres , var - > bits_per_pixel ) ;
return - EINVAL ;
}
if ( v . yres_virtual < v . yres )
v . yres_virtual = v . yres ;
if ( v . xres_virtual < v . xres )
v . xres_virtual = v . xres ;
/* XXX I'm adjusting xres_virtual to the pitch, that may help XFree
* with some panels , though I don ' t quite like this solution
*/
if ( rinfo - > info - > flags & FBINFO_HWACCEL_DISABLED ) {
v . xres_virtual = v . xres_virtual & ~ 7ul ;
} else {
pitch = ( ( v . xres_virtual * ( ( v . bits_per_pixel + 1 ) / 8 ) + 0x3f )
& ~ ( 0x3f ) ) > > 6 ;
v . xres_virtual = ( pitch < < 6 ) / ( ( v . bits_per_pixel + 1 ) / 8 ) ;
}
if ( ( ( v . xres_virtual * v . yres_virtual * nom ) / den ) > rinfo - > mapped_vram )
return - EINVAL ;
if ( v . xres_virtual < v . xres )
v . xres = v . xres_virtual ;
if ( v . xoffset < 0 )
v . xoffset = 0 ;
if ( v . yoffset < 0 )
v . yoffset = 0 ;
if ( v . xoffset > v . xres_virtual - v . xres )
v . xoffset = v . xres_virtual - v . xres - 1 ;
if ( v . yoffset > v . yres_virtual - v . yres )
v . yoffset = v . yres_virtual - v . yres - 1 ;
v . red . msb_right = v . green . msb_right = v . blue . msb_right =
v . transp . offset = v . transp . length =
v . transp . msb_right = 0 ;
memcpy ( var , & v , sizeof ( v ) ) ;
return 0 ;
}
static int radeonfb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info )
{
struct radeonfb_info * rinfo = info - > par ;
if ( ( var - > xoffset + var - > xres > var - > xres_virtual )
| | ( var - > yoffset + var - > yres > var - > yres_virtual ) )
return - EINVAL ;
if ( rinfo - > asleep )
return 0 ;
radeon_fifo_wait ( 2 ) ;
OUTREG ( CRTC_OFFSET , ( ( var - > yoffset * var - > xres_virtual + var - > xoffset )
* var - > bits_per_pixel / 8 ) & ~ 7 ) ;
return 0 ;
}
2006-01-14 13:21:25 -08:00
static int radeonfb_ioctl ( struct fb_info * info , unsigned int cmd ,
unsigned long arg )
2005-04-16 15:20:36 -07:00
{
struct radeonfb_info * rinfo = info - > par ;
unsigned int tmp ;
u32 value = 0 ;
int rc ;
switch ( cmd ) {
/*
* TODO : set mirror accordingly for non - Mobility chipsets with 2 CRTC ' s
* and do something better using 2 nd CRTC instead of just hackish
* routing to second output
*/
case FBIO_RADEON_SET_MIRROR :
if ( ! rinfo - > is_mobility )
return - EINVAL ;
rc = get_user ( value , ( __u32 __user * ) arg ) ;
if ( rc )
return rc ;
radeon_fifo_wait ( 2 ) ;
if ( value & 0x01 ) {
tmp = INREG ( LVDS_GEN_CNTL ) ;
tmp | = ( LVDS_ON | LVDS_BLON ) ;
} else {
tmp = INREG ( LVDS_GEN_CNTL ) ;
tmp & = ~ ( LVDS_ON | LVDS_BLON ) ;
}
OUTREG ( LVDS_GEN_CNTL , tmp ) ;
if ( value & 0x02 ) {
tmp = INREG ( CRTC_EXT_CNTL ) ;
tmp | = CRTC_CRT_ON ;
mirror = 1 ;
} else {
tmp = INREG ( CRTC_EXT_CNTL ) ;
tmp & = ~ CRTC_CRT_ON ;
mirror = 0 ;
}
OUTREG ( CRTC_EXT_CNTL , tmp ) ;
return 0 ;
case FBIO_RADEON_GET_MIRROR :
if ( ! rinfo - > is_mobility )
return - EINVAL ;
tmp = INREG ( LVDS_GEN_CNTL ) ;
if ( ( LVDS_ON | LVDS_BLON ) & tmp )
value | = 0x01 ;
tmp = INREG ( CRTC_EXT_CNTL ) ;
if ( CRTC_CRT_ON & tmp )
value | = 0x02 ;
return put_user ( value , ( __u32 __user * ) arg ) ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
int radeon_screen_blank ( struct radeonfb_info * rinfo , int blank , int mode_switch )
{
u32 val ;
u32 tmp_pix_clks ;
int unblank = 0 ;
if ( rinfo - > lock_blank )
return 0 ;
radeon_engine_idle ( ) ;
val = INREG ( CRTC_EXT_CNTL ) ;
val & = ~ ( CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
CRTC_VSYNC_DIS ) ;
switch ( blank ) {
case FB_BLANK_VSYNC_SUSPEND :
val | = ( CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS ) ;
break ;
case FB_BLANK_HSYNC_SUSPEND :
val | = ( CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS ) ;
break ;
case FB_BLANK_POWERDOWN :
val | = ( CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
CRTC_HSYNC_DIS ) ;
break ;
case FB_BLANK_NORMAL :
val | = CRTC_DISPLAY_DIS ;
break ;
case FB_BLANK_UNBLANK :
default :
unblank = 1 ;
}
OUTREG ( CRTC_EXT_CNTL , val ) ;
switch ( rinfo - > mon1_type ) {
case MT_DFP :
if ( unblank )
OUTREGP ( FP_GEN_CNTL , ( FP_FPON | FP_TMDS_EN ) ,
~ ( FP_FPON | FP_TMDS_EN ) ) ;
else {
if ( mode_switch | | blank = = FB_BLANK_NORMAL )
break ;
OUTREGP ( FP_GEN_CNTL , 0 , ~ ( FP_FPON | FP_TMDS_EN ) ) ;
}
break ;
case MT_LCD :
del_timer_sync ( & rinfo - > lvds_timer ) ;
val = INREG ( LVDS_GEN_CNTL ) ;
if ( unblank ) {
u32 target_val = ( val & ~ LVDS_DISPLAY_DIS ) | LVDS_BLON | LVDS_ON
| LVDS_EN | ( rinfo - > init_state . lvds_gen_cntl
& ( LVDS_DIGON | LVDS_BL_MOD_EN ) ) ;
if ( ( val ^ target_val ) = = LVDS_DISPLAY_DIS )
OUTREG ( LVDS_GEN_CNTL , target_val ) ;
else if ( ( val ^ target_val ) ! = 0 ) {
OUTREG ( LVDS_GEN_CNTL , target_val
& ~ ( LVDS_ON | LVDS_BL_MOD_EN ) ) ;
rinfo - > init_state . lvds_gen_cntl & = ~ LVDS_STATE_MASK ;
rinfo - > init_state . lvds_gen_cntl | =
target_val & LVDS_STATE_MASK ;
if ( mode_switch ) {
radeon_msleep ( rinfo - > panel_info . pwr_delay ) ;
OUTREG ( LVDS_GEN_CNTL , target_val ) ;
}
else {
rinfo - > pending_lvds_gen_cntl = target_val ;
mod_timer ( & rinfo - > lvds_timer ,
jiffies +
msecs_to_jiffies ( rinfo - > panel_info . pwr_delay ) ) ;
}
}
} else {
val | = LVDS_DISPLAY_DIS ;
OUTREG ( LVDS_GEN_CNTL , val ) ;
/* We don't do a full switch-off on a simple mode switch */
if ( mode_switch | | blank = = FB_BLANK_NORMAL )
break ;
/* Asic bug, when turning off LVDS_ON, we have to make sure
* RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
*/
tmp_pix_clks = INPLL ( PIXCLKS_CNTL ) ;
if ( rinfo - > is_mobility | | rinfo - > is_IGP )
OUTPLLP ( PIXCLKS_CNTL , 0 , ~ PIXCLK_LVDS_ALWAYS_ONb ) ;
val & = ~ ( LVDS_BL_MOD_EN ) ;
OUTREG ( LVDS_GEN_CNTL , val ) ;
udelay ( 100 ) ;
val & = ~ ( LVDS_ON | LVDS_EN ) ;
OUTREG ( LVDS_GEN_CNTL , val ) ;
val & = ~ LVDS_DIGON ;
rinfo - > pending_lvds_gen_cntl = val ;
mod_timer ( & rinfo - > lvds_timer ,
jiffies +
msecs_to_jiffies ( rinfo - > panel_info . pwr_delay ) ) ;
rinfo - > init_state . lvds_gen_cntl & = ~ LVDS_STATE_MASK ;
rinfo - > init_state . lvds_gen_cntl | = val & LVDS_STATE_MASK ;
if ( rinfo - > is_mobility | | rinfo - > is_IGP )
OUTPLL ( PIXCLKS_CNTL , tmp_pix_clks ) ;
}
break ;
case MT_CRT :
// todo: powerdown DAC
default :
break ;
}
2007-03-01 18:29:14 -08:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
static int radeonfb_blank ( int blank , struct fb_info * info )
{
struct radeonfb_info * rinfo = info - > par ;
if ( rinfo - > asleep )
return 0 ;
return radeon_screen_blank ( rinfo , blank , 0 ) ;
}
2005-05-01 08:59:22 -07:00
static int radeon_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct radeonfb_info * rinfo )
2005-04-16 15:20:36 -07:00
{
u32 pindex ;
unsigned int i ;
2005-05-01 08:59:22 -07:00
2005-04-16 15:20:36 -07:00
if ( regno > 255 )
2006-03-27 01:17:30 -08:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
red > > = 8 ;
green > > = 8 ;
blue > > = 8 ;
rinfo - > palette [ regno ] . red = red ;
rinfo - > palette [ regno ] . green = green ;
rinfo - > palette [ regno ] . blue = blue ;
/* default */
pindex = regno ;
if ( ! rinfo - > asleep ) {
radeon_fifo_wait ( 9 ) ;
if ( rinfo - > bpp = = 16 ) {
pindex = regno * 8 ;
if ( rinfo - > depth = = 16 & & regno > 63 )
2006-03-27 01:17:30 -08:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
if ( rinfo - > depth = = 15 & & regno > 31 )
2006-03-27 01:17:30 -08:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2005-05-01 08:59:22 -07:00
/* For 565, the green component is mixed one order
* below
*/
2005-04-16 15:20:36 -07:00
if ( rinfo - > depth = = 16 ) {
OUTREG ( PALETTE_INDEX , pindex > > 1 ) ;
2005-05-01 08:59:22 -07:00
OUTREG ( PALETTE_DATA ,
( rinfo - > palette [ regno > > 1 ] . red < < 16 ) |
( green < < 8 ) |
( rinfo - > palette [ regno > > 1 ] . blue ) ) ;
2005-04-16 15:20:36 -07:00
green = rinfo - > palette [ regno < < 1 ] . green ;
}
}
if ( rinfo - > depth ! = 16 | | regno < 32 ) {
OUTREG ( PALETTE_INDEX , pindex ) ;
2005-05-01 08:59:22 -07:00
OUTREG ( PALETTE_DATA , ( red < < 16 ) |
( green < < 8 ) | blue ) ;
2005-04-16 15:20:36 -07:00
}
}
if ( regno < 16 ) {
2005-05-01 08:59:22 -07:00
u32 * pal = rinfo - > info - > pseudo_palette ;
2005-04-16 15:20:36 -07:00
switch ( rinfo - > depth ) {
case 15 :
pal [ regno ] = ( regno < < 10 ) | ( regno < < 5 ) | regno ;
break ;
case 16 :
pal [ regno ] = ( regno < < 11 ) | ( regno < < 5 ) | regno ;
break ;
case 24 :
pal [ regno ] = ( regno < < 16 ) | ( regno < < 8 ) | regno ;
break ;
case 32 :
i = ( regno < < 8 ) | regno ;
pal [ regno ] = ( i < < 16 ) | i ;
break ;
}
}
return 0 ;
}
2005-05-01 08:59:22 -07:00
static int radeonfb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info )
{
struct radeonfb_info * rinfo = info - > par ;
u32 dac_cntl2 , vclk_cntl = 0 ;
int rc ;
if ( ! rinfo - > asleep ) {
if ( rinfo - > is_mobility ) {
vclk_cntl = INPLL ( VCLK_ECP_CNTL ) ;
OUTPLL ( VCLK_ECP_CNTL ,
vclk_cntl & ~ PIXCLK_DAC_ALWAYS_ONb ) ;
}
/* Make sure we are on first palette */
if ( rinfo - > has_CRTC2 ) {
dac_cntl2 = INREG ( DAC_CNTL2 ) ;
dac_cntl2 & = ~ DAC2_PALETTE_ACCESS_CNTL ;
OUTREG ( DAC_CNTL2 , dac_cntl2 ) ;
}
}
rc = radeon_setcolreg ( regno , red , green , blue , transp , rinfo ) ;
if ( ! rinfo - > asleep & & rinfo - > is_mobility )
OUTPLL ( VCLK_ECP_CNTL , vclk_cntl ) ;
return rc ;
}
static int radeonfb_setcmap ( struct fb_cmap * cmap , struct fb_info * info )
{
struct radeonfb_info * rinfo = info - > par ;
u16 * red , * green , * blue , * transp ;
u32 dac_cntl2 , vclk_cntl = 0 ;
int i , start , rc = 0 ;
if ( ! rinfo - > asleep ) {
if ( rinfo - > is_mobility ) {
vclk_cntl = INPLL ( VCLK_ECP_CNTL ) ;
OUTPLL ( VCLK_ECP_CNTL ,
vclk_cntl & ~ PIXCLK_DAC_ALWAYS_ONb ) ;
}
/* Make sure we are on first palette */
if ( rinfo - > has_CRTC2 ) {
dac_cntl2 = INREG ( DAC_CNTL2 ) ;
dac_cntl2 & = ~ DAC2_PALETTE_ACCESS_CNTL ;
OUTREG ( DAC_CNTL2 , dac_cntl2 ) ;
}
}
red = cmap - > red ;
green = cmap - > green ;
blue = cmap - > blue ;
transp = cmap - > transp ;
start = cmap - > start ;
for ( i = 0 ; i < cmap - > len ; i + + ) {
u_int hred , hgreen , hblue , htransp = 0xffff ;
hred = * red + + ;
hgreen = * green + + ;
hblue = * blue + + ;
if ( transp )
htransp = * transp + + ;
rc = radeon_setcolreg ( start + + , hred , hgreen , hblue , htransp ,
rinfo ) ;
if ( rc )
break ;
}
if ( ! rinfo - > asleep & & rinfo - > is_mobility )
OUTPLL ( VCLK_ECP_CNTL , vclk_cntl ) ;
return rc ;
}
2005-04-16 15:20:36 -07:00
static void radeon_save_state ( struct radeonfb_info * rinfo ,
struct radeon_regs * save )
{
/* CRTC regs */
save - > crtc_gen_cntl = INREG ( CRTC_GEN_CNTL ) ;
save - > crtc_ext_cntl = INREG ( CRTC_EXT_CNTL ) ;
save - > crtc_more_cntl = INREG ( CRTC_MORE_CNTL ) ;
save - > dac_cntl = INREG ( DAC_CNTL ) ;
save - > crtc_h_total_disp = INREG ( CRTC_H_TOTAL_DISP ) ;
save - > crtc_h_sync_strt_wid = INREG ( CRTC_H_SYNC_STRT_WID ) ;
save - > crtc_v_total_disp = INREG ( CRTC_V_TOTAL_DISP ) ;
save - > crtc_v_sync_strt_wid = INREG ( CRTC_V_SYNC_STRT_WID ) ;
save - > crtc_pitch = INREG ( CRTC_PITCH ) ;
save - > surface_cntl = INREG ( SURFACE_CNTL ) ;
/* FP regs */
save - > fp_crtc_h_total_disp = INREG ( FP_CRTC_H_TOTAL_DISP ) ;
save - > fp_crtc_v_total_disp = INREG ( FP_CRTC_V_TOTAL_DISP ) ;
save - > fp_gen_cntl = INREG ( FP_GEN_CNTL ) ;
save - > fp_h_sync_strt_wid = INREG ( FP_H_SYNC_STRT_WID ) ;
save - > fp_horz_stretch = INREG ( FP_HORZ_STRETCH ) ;
save - > fp_v_sync_strt_wid = INREG ( FP_V_SYNC_STRT_WID ) ;
save - > fp_vert_stretch = INREG ( FP_VERT_STRETCH ) ;
save - > lvds_gen_cntl = INREG ( LVDS_GEN_CNTL ) ;
save - > lvds_pll_cntl = INREG ( LVDS_PLL_CNTL ) ;
save - > tmds_crc = INREG ( TMDS_CRC ) ;
save - > tmds_transmitter_cntl = INREG ( TMDS_TRANSMITTER_CNTL ) ;
save - > vclk_ecp_cntl = INPLL ( VCLK_ECP_CNTL ) ;
/* PLL regs */
save - > clk_cntl_index = INREG ( CLOCK_CNTL_INDEX ) & ~ 0x3f ;
radeon_pll_errata_after_index ( rinfo ) ;
save - > ppll_div_3 = INPLL ( PPLL_DIV_3 ) ;
save - > ppll_ref_div = INPLL ( PPLL_REF_DIV ) ;
}
static void radeon_write_pll_regs ( struct radeonfb_info * rinfo , struct radeon_regs * mode )
{
int i ;
radeon_fifo_wait ( 20 ) ;
/* Workaround from XFree */
if ( rinfo - > is_mobility ) {
/* A temporal workaround for the occational blanking on certain laptop
* panels . This appears to related to the PLL divider registers
* ( fail to lock ? ) . It occurs even when all dividers are the same
* with their old settings . In this case we really don ' t need to
* fiddle with PLL registers . By doing this we can avoid the blanking
* problem with some panels .
*/
if ( ( mode - > ppll_ref_div = = ( INPLL ( PPLL_REF_DIV ) & PPLL_REF_DIV_MASK ) ) & &
( mode - > ppll_div_3 = = ( INPLL ( PPLL_DIV_3 ) &
( PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK ) ) ) ) {
/* We still have to force a switch to selected PPLL div thanks to
* an XFree86 driver bug which will switch it away in some cases
* even when using UseFDev */
OUTREGP ( CLOCK_CNTL_INDEX ,
mode - > clk_cntl_index & PPLL_DIV_SEL_MASK ,
~ PPLL_DIV_SEL_MASK ) ;
radeon_pll_errata_after_index ( rinfo ) ;
radeon_pll_errata_after_data ( rinfo ) ;
return ;
}
}
/* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
OUTPLLP ( VCLK_ECP_CNTL , VCLK_SRC_SEL_CPUCLK , ~ VCLK_SRC_SEL_MASK ) ;
/* Reset PPLL & enable atomic update */
OUTPLLP ( PPLL_CNTL ,
PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN ,
~ ( PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN ) ) ;
/* Switch to selected PPLL divider */
OUTREGP ( CLOCK_CNTL_INDEX ,
mode - > clk_cntl_index & PPLL_DIV_SEL_MASK ,
~ PPLL_DIV_SEL_MASK ) ;
radeon_pll_errata_after_index ( rinfo ) ;
radeon_pll_errata_after_data ( rinfo ) ;
/* Set PPLL ref. div */
if ( rinfo - > family = = CHIP_FAMILY_R300 | |
rinfo - > family = = CHIP_FAMILY_RS300 | |
rinfo - > family = = CHIP_FAMILY_R350 | |
rinfo - > family = = CHIP_FAMILY_RV350 ) {
if ( mode - > ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK ) {
/* When restoring console mode, use saved PPLL_REF_DIV
* setting .
*/
OUTPLLP ( PPLL_REF_DIV , mode - > ppll_ref_div , 0 ) ;
} else {
/* R300 uses ref_div_acc field as real ref divider */
OUTPLLP ( PPLL_REF_DIV ,
( mode - > ppll_ref_div < < R300_PPLL_REF_DIV_ACC_SHIFT ) ,
~ R300_PPLL_REF_DIV_ACC_MASK ) ;
}
} else
OUTPLLP ( PPLL_REF_DIV , mode - > ppll_ref_div , ~ PPLL_REF_DIV_MASK ) ;
/* Set PPLL divider 3 & post divider*/
OUTPLLP ( PPLL_DIV_3 , mode - > ppll_div_3 , ~ PPLL_FB3_DIV_MASK ) ;
OUTPLLP ( PPLL_DIV_3 , mode - > ppll_div_3 , ~ PPLL_POST3_DIV_MASK ) ;
/* Write update */
while ( INPLL ( PPLL_REF_DIV ) & PPLL_ATOMIC_UPDATE_R )
;
OUTPLLP ( PPLL_REF_DIV , PPLL_ATOMIC_UPDATE_W , ~ PPLL_ATOMIC_UPDATE_W ) ;
/* Wait read update complete */
/* FIXME: Certain revisions of R300 can't recover here. Not sure of
the cause yet , but this workaround will mask the problem for now .
Other chips usually will pass at the very first test , so the
workaround shouldn ' t have any effect on them . */
for ( i = 0 ; ( i < 10000 & & INPLL ( PPLL_REF_DIV ) & PPLL_ATOMIC_UPDATE_R ) ; i + + )
;
OUTPLL ( HTOTAL_CNTL , 0 ) ;
/* Clear reset & atomic update */
OUTPLLP ( PPLL_CNTL , 0 ,
~ ( PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN ) ) ;
/* We may want some locking ... oh well */
radeon_msleep ( 5 ) ;
/* Switch back VCLK source to PPLL */
OUTPLLP ( VCLK_ECP_CNTL , VCLK_SRC_SEL_PPLLCLK , ~ VCLK_SRC_SEL_MASK ) ;
}
/*
* Timer function for delayed LVDS panel power up / down
*/
static void radeon_lvds_timer_func ( unsigned long data )
{
struct radeonfb_info * rinfo = ( struct radeonfb_info * ) data ;
radeon_engine_idle ( ) ;
OUTREG ( LVDS_GEN_CNTL , rinfo - > pending_lvds_gen_cntl ) ;
}
/*
* Apply a video mode . This will apply the whole register set , including
* the PLL registers , to the card
*/
void radeon_write_mode ( struct radeonfb_info * rinfo , struct radeon_regs * mode ,
int regs_only )
{
int i ;
int primary_mon = PRIMARY_MONITOR ( rinfo ) ;
if ( nomodeset )
return ;
if ( ! regs_only )
radeon_screen_blank ( rinfo , FB_BLANK_NORMAL , 0 ) ;
radeon_fifo_wait ( 31 ) ;
for ( i = 0 ; i < 10 ; i + + )
OUTREG ( common_regs [ i ] . reg , common_regs [ i ] . val ) ;
/* Apply surface registers */
for ( i = 0 ; i < 8 ; i + + ) {
OUTREG ( SURFACE0_LOWER_BOUND + 0x10 * i , mode - > surf_lower_bound [ i ] ) ;
OUTREG ( SURFACE0_UPPER_BOUND + 0x10 * i , mode - > surf_upper_bound [ i ] ) ;
OUTREG ( SURFACE0_INFO + 0x10 * i , mode - > surf_info [ i ] ) ;
}
OUTREG ( CRTC_GEN_CNTL , mode - > crtc_gen_cntl ) ;
OUTREGP ( CRTC_EXT_CNTL , mode - > crtc_ext_cntl ,
~ ( CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS ) ) ;
OUTREG ( CRTC_MORE_CNTL , mode - > crtc_more_cntl ) ;
OUTREGP ( DAC_CNTL , mode - > dac_cntl , DAC_RANGE_CNTL | DAC_BLANKING ) ;
OUTREG ( CRTC_H_TOTAL_DISP , mode - > crtc_h_total_disp ) ;
OUTREG ( CRTC_H_SYNC_STRT_WID , mode - > crtc_h_sync_strt_wid ) ;
OUTREG ( CRTC_V_TOTAL_DISP , mode - > crtc_v_total_disp ) ;
OUTREG ( CRTC_V_SYNC_STRT_WID , mode - > crtc_v_sync_strt_wid ) ;
OUTREG ( CRTC_OFFSET , 0 ) ;
OUTREG ( CRTC_OFFSET_CNTL , 0 ) ;
OUTREG ( CRTC_PITCH , mode - > crtc_pitch ) ;
OUTREG ( SURFACE_CNTL , mode - > surface_cntl ) ;
radeon_write_pll_regs ( rinfo , mode ) ;
if ( ( primary_mon = = MT_DFP ) | | ( primary_mon = = MT_LCD ) ) {
radeon_fifo_wait ( 10 ) ;
OUTREG ( FP_CRTC_H_TOTAL_DISP , mode - > fp_crtc_h_total_disp ) ;
OUTREG ( FP_CRTC_V_TOTAL_DISP , mode - > fp_crtc_v_total_disp ) ;
OUTREG ( FP_H_SYNC_STRT_WID , mode - > fp_h_sync_strt_wid ) ;
OUTREG ( FP_V_SYNC_STRT_WID , mode - > fp_v_sync_strt_wid ) ;
OUTREG ( FP_HORZ_STRETCH , mode - > fp_horz_stretch ) ;
OUTREG ( FP_VERT_STRETCH , mode - > fp_vert_stretch ) ;
OUTREG ( FP_GEN_CNTL , mode - > fp_gen_cntl ) ;
OUTREG ( TMDS_CRC , mode - > tmds_crc ) ;
OUTREG ( TMDS_TRANSMITTER_CNTL , mode - > tmds_transmitter_cntl ) ;
}
if ( ! regs_only )
radeon_screen_blank ( rinfo , FB_BLANK_UNBLANK , 0 ) ;
radeon_fifo_wait ( 2 ) ;
OUTPLL ( VCLK_ECP_CNTL , mode - > vclk_ecp_cntl ) ;
return ;
}
/*
* Calculate the PLL values for a given mode
*/
static void radeon_calc_pll_regs ( struct radeonfb_info * rinfo , struct radeon_regs * regs ,
unsigned long freq )
{
const struct {
int divider ;
int bitvalue ;
} * post_div ,
post_divs [ ] = {
{ 1 , 0 } ,
{ 2 , 1 } ,
{ 4 , 2 } ,
{ 8 , 3 } ,
{ 3 , 4 } ,
{ 16 , 5 } ,
{ 6 , 6 } ,
{ 12 , 7 } ,
{ 0 , 0 } ,
} ;
int fb_div , pll_output_freq = 0 ;
int uses_dvo = 0 ;
/* Check if the DVO port is enabled and sourced from the primary CRTC. I'm
* not sure which model starts having FP2_GEN_CNTL , I assume anything more
* recent than an r ( v ) 100. . .
*/
# if 1
/* XXX I had reports of flicker happening with the cinema display
* on TMDS1 that seem to be fixed if I also forbit odd dividers in
* this case . This could just be a bandwidth calculation issue , I
* haven ' t implemented the bandwidth code yet , but in the meantime ,
* forcing uses_dvo to 1 fixes it and shouln ' t have bad side effects ,
* I haven ' t seen a case were were absolutely needed an odd PLL
* divider . I ' ll find a better fix once I have more infos on the
* real cause of the problem .
*/
while ( rinfo - > has_CRTC2 ) {
u32 fp2_gen_cntl = INREG ( FP2_GEN_CNTL ) ;
u32 disp_output_cntl ;
int source ;
/* FP2 path not enabled */
if ( ( fp2_gen_cntl & FP2_ON ) = = 0 )
break ;
/* Not all chip revs have the same format for this register,
* extract the source selection
*/
if ( rinfo - > family = = CHIP_FAMILY_R200 | |
rinfo - > family = = CHIP_FAMILY_R300 | |
rinfo - > family = = CHIP_FAMILY_R350 | |
rinfo - > family = = CHIP_FAMILY_RV350 ) {
source = ( fp2_gen_cntl > > 10 ) & 0x3 ;
/* sourced from transform unit, check for transform unit
* own source
*/
if ( source = = 3 ) {
disp_output_cntl = INREG ( DISP_OUTPUT_CNTL ) ;
source = ( disp_output_cntl > > 12 ) & 0x3 ;
}
} else
source = ( fp2_gen_cntl > > 13 ) & 0x1 ;
/* sourced from CRTC2 -> exit */
if ( source = = 1 )
break ;
/* so we end up on CRTC1, let's set uses_dvo to 1 now */
uses_dvo = 1 ;
break ;
}
# else
uses_dvo = 1 ;
# endif
if ( freq > rinfo - > pll . ppll_max )
freq = rinfo - > pll . ppll_max ;
if ( freq * 12 < rinfo - > pll . ppll_min )
freq = rinfo - > pll . ppll_min / 12 ;
RTRACE ( " freq = %lu, PLL min = %u, PLL max = %u \n " ,
freq , rinfo - > pll . ppll_min , rinfo - > pll . ppll_max ) ;
for ( post_div = & post_divs [ 0 ] ; post_div - > divider ; + + post_div ) {
pll_output_freq = post_div - > divider * freq ;
/* If we output to the DVO port (external TMDS), we don't allow an
* odd PLL divider as those aren ' t supported on this path
*/
if ( uses_dvo & & ( post_div - > divider & 1 ) )
continue ;
if ( pll_output_freq > = rinfo - > pll . ppll_min & &
pll_output_freq < = rinfo - > pll . ppll_max )
break ;
}
/* If we fall through the bottom, try the "default value"
given by the terminal post_div - > bitvalue */
if ( ! post_div - > divider ) {
post_div = & post_divs [ post_div - > bitvalue ] ;
pll_output_freq = post_div - > divider * freq ;
}
RTRACE ( " ref_div = %d, ref_clk = %d, output_freq = %d \n " ,
rinfo - > pll . ref_div , rinfo - > pll . ref_clk ,
pll_output_freq ) ;
/* If we fall through the bottom, try the "default value"
given by the terminal post_div - > bitvalue */
if ( ! post_div - > divider ) {
post_div = & post_divs [ post_div - > bitvalue ] ;
pll_output_freq = post_div - > divider * freq ;
}
RTRACE ( " ref_div = %d, ref_clk = %d, output_freq = %d \n " ,
rinfo - > pll . ref_div , rinfo - > pll . ref_clk ,
pll_output_freq ) ;
fb_div = round_div ( rinfo - > pll . ref_div * pll_output_freq ,
rinfo - > pll . ref_clk ) ;
regs - > ppll_ref_div = rinfo - > pll . ref_div ;
regs - > ppll_div_3 = fb_div | ( post_div - > bitvalue < < 16 ) ;
RTRACE ( " post div = 0x%x \n " , post_div - > bitvalue ) ;
RTRACE ( " fb_div = 0x%x \n " , fb_div ) ;
RTRACE ( " ppll_div_3 = 0x%x \n " , regs - > ppll_div_3 ) ;
}
static int radeonfb_set_par ( struct fb_info * info )
{
struct radeonfb_info * rinfo = info - > par ;
struct fb_var_screeninfo * mode = & info - > var ;
struct radeon_regs * newmode ;
int hTotal , vTotal , hSyncStart , hSyncEnd ,
hSyncPol , vSyncStart , vSyncEnd , vSyncPol , cSync ;
u8 hsync_adj_tab [ ] = { 0 , 0x12 , 9 , 9 , 6 , 5 } ;
u8 hsync_fudge_fp [ ] = { 2 , 2 , 0 , 0 , 5 , 5 } ;
u32 sync , h_sync_pol , v_sync_pol , dotClock , pixClock ;
int i , freq ;
int format = 0 ;
int nopllcalc = 0 ;
int hsync_start , hsync_fudge , bytpp , hsync_wid , vsync_wid ;
int primary_mon = PRIMARY_MONITOR ( rinfo ) ;
int depth = var_to_depth ( mode ) ;
int use_rmx = 0 ;
newmode = kmalloc ( sizeof ( struct radeon_regs ) , GFP_KERNEL ) ;
if ( ! newmode )
return - ENOMEM ;
/* We always want engine to be idle on a mode switch, even
* if we won ' t actually change the mode
*/
radeon_engine_idle ( ) ;
hSyncStart = mode - > xres + mode - > right_margin ;
hSyncEnd = hSyncStart + mode - > hsync_len ;
hTotal = hSyncEnd + mode - > left_margin ;
vSyncStart = mode - > yres + mode - > lower_margin ;
vSyncEnd = vSyncStart + mode - > vsync_len ;
vTotal = vSyncEnd + mode - > upper_margin ;
pixClock = mode - > pixclock ;
sync = mode - > sync ;
h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1 ;
v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1 ;
if ( primary_mon = = MT_DFP | | primary_mon = = MT_LCD ) {
if ( rinfo - > panel_info . xres < mode - > xres )
mode - > xres = rinfo - > panel_info . xres ;
if ( rinfo - > panel_info . yres < mode - > yres )
mode - > yres = rinfo - > panel_info . yres ;
hTotal = mode - > xres + rinfo - > panel_info . hblank ;
hSyncStart = mode - > xres + rinfo - > panel_info . hOver_plus ;
hSyncEnd = hSyncStart + rinfo - > panel_info . hSync_width ;
vTotal = mode - > yres + rinfo - > panel_info . vblank ;
vSyncStart = mode - > yres + rinfo - > panel_info . vOver_plus ;
vSyncEnd = vSyncStart + rinfo - > panel_info . vSync_width ;
h_sync_pol = ! rinfo - > panel_info . hAct_high ;
v_sync_pol = ! rinfo - > panel_info . vAct_high ;
pixClock = 100000000 / rinfo - > panel_info . clock ;
if ( rinfo - > panel_info . use_bios_dividers ) {
nopllcalc = 1 ;
newmode - > ppll_div_3 = rinfo - > panel_info . fbk_divider |
( rinfo - > panel_info . post_divider < < 16 ) ;
newmode - > ppll_ref_div = rinfo - > panel_info . ref_divider ;
}
}
dotClock = 1000000000 / pixClock ;
freq = dotClock / 10 ; /* x100 */
RTRACE ( " hStart = %d, hEnd = %d, hTotal = %d \n " ,
hSyncStart , hSyncEnd , hTotal ) ;
RTRACE ( " vStart = %d, vEnd = %d, vTotal = %d \n " ,
vSyncStart , vSyncEnd , vTotal ) ;
hsync_wid = ( hSyncEnd - hSyncStart ) / 8 ;
vsync_wid = vSyncEnd - vSyncStart ;
if ( hsync_wid = = 0 )
hsync_wid = 1 ;
else if ( hsync_wid > 0x3f ) /* max */
hsync_wid = 0x3f ;
if ( vsync_wid = = 0 )
vsync_wid = 1 ;
else if ( vsync_wid > 0x1f ) /* max */
vsync_wid = 0x1f ;
hSyncPol = mode - > sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1 ;
vSyncPol = mode - > sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1 ;
cSync = mode - > sync & FB_SYNC_COMP_HIGH_ACT ? ( 1 < < 4 ) : 0 ;
format = radeon_get_dstbpp ( depth ) ;
bytpp = mode - > bits_per_pixel > > 3 ;
if ( ( primary_mon = = MT_DFP ) | | ( primary_mon = = MT_LCD ) )
hsync_fudge = hsync_fudge_fp [ format - 1 ] ;
else
hsync_fudge = hsync_adj_tab [ format - 1 ] ;
hsync_start = hSyncStart - 8 + hsync_fudge ;
newmode - > crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
( format < < 8 ) ;
/* Clear auto-center etc... */
newmode - > crtc_more_cntl = rinfo - > init_state . crtc_more_cntl ;
newmode - > crtc_more_cntl & = 0xfffffff0 ;
if ( ( primary_mon = = MT_DFP ) | | ( primary_mon = = MT_LCD ) ) {
newmode - > crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN ;
if ( mirror )
newmode - > crtc_ext_cntl | = CRTC_CRT_ON ;
newmode - > crtc_gen_cntl & = ~ ( CRTC_DBL_SCAN_EN |
CRTC_INTERLACE_EN ) ;
} else {
newmode - > crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
CRTC_CRT_ON ;
}
newmode - > dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
DAC_8BIT_EN ;
newmode - > crtc_h_total_disp = ( ( ( ( hTotal / 8 ) - 1 ) & 0x3ff ) |
( ( ( mode - > xres / 8 ) - 1 ) < < 16 ) ) ;
newmode - > crtc_h_sync_strt_wid = ( ( hsync_start & 0x1fff ) |
( hsync_wid < < 16 ) | ( h_sync_pol < < 23 ) ) ;
newmode - > crtc_v_total_disp = ( ( vTotal - 1 ) & 0xffff ) |
( ( mode - > yres - 1 ) < < 16 ) ;
newmode - > crtc_v_sync_strt_wid = ( ( ( vSyncStart - 1 ) & 0xfff ) |
( vsync_wid < < 16 ) | ( v_sync_pol < < 23 ) ) ;
if ( ! ( info - > flags & FBINFO_HWACCEL_DISABLED ) ) {
/* We first calculate the engine pitch */
rinfo - > pitch = ( ( mode - > xres_virtual * ( ( mode - > bits_per_pixel + 1 ) / 8 ) + 0x3f )
& ~ ( 0x3f ) ) > > 6 ;
/* Then, re-multiply it to get the CRTC pitch */
newmode - > crtc_pitch = ( rinfo - > pitch < < 3 ) / ( ( mode - > bits_per_pixel + 1 ) / 8 ) ;
} else
newmode - > crtc_pitch = ( mode - > xres_virtual > > 3 ) ;
newmode - > crtc_pitch | = ( newmode - > crtc_pitch < < 16 ) ;
/*
* It looks like recent chips have a problem with SURFACE_CNTL ,
* setting SURF_TRANSLATION_DIS completely disables the
* swapper as well , so we leave it unset now .
*/
newmode - > surface_cntl = 0 ;
# if defined(__BIG_ENDIAN)
/* Setup swapping on both apertures, though we currently
* only use aperture 0 , enabling swapper on aperture 1
* won ' t harm
*/
switch ( mode - > bits_per_pixel ) {
case 16 :
newmode - > surface_cntl | = NONSURF_AP0_SWP_16BPP ;
newmode - > surface_cntl | = NONSURF_AP1_SWP_16BPP ;
break ;
case 24 :
case 32 :
newmode - > surface_cntl | = NONSURF_AP0_SWP_32BPP ;
newmode - > surface_cntl | = NONSURF_AP1_SWP_32BPP ;
break ;
}
# endif
/* Clear surface registers */
for ( i = 0 ; i < 8 ; i + + ) {
newmode - > surf_lower_bound [ i ] = 0 ;
newmode - > surf_upper_bound [ i ] = 0x1f ;
newmode - > surf_info [ i ] = 0 ;
}
RTRACE ( " h_total_disp = 0x%x \t hsync_strt_wid = 0x%x \n " ,
newmode - > crtc_h_total_disp , newmode - > crtc_h_sync_strt_wid ) ;
RTRACE ( " v_total_disp = 0x%x \t vsync_strt_wid = 0x%x \n " ,
newmode - > crtc_v_total_disp , newmode - > crtc_v_sync_strt_wid ) ;
rinfo - > bpp = mode - > bits_per_pixel ;
rinfo - > depth = depth ;
RTRACE ( " pixclock = %lu \n " , ( unsigned long ) pixClock ) ;
RTRACE ( " freq = %lu \n " , ( unsigned long ) freq ) ;
/* We use PPLL_DIV_3 */
newmode - > clk_cntl_index = 0x300 ;
/* Calculate PPLL value if necessary */
if ( ! nopllcalc )
radeon_calc_pll_regs ( rinfo , newmode , freq ) ;
newmode - > vclk_ecp_cntl = rinfo - > init_state . vclk_ecp_cntl ;
if ( ( primary_mon = = MT_DFP ) | | ( primary_mon = = MT_LCD ) ) {
unsigned int hRatio , vRatio ;
if ( mode - > xres > rinfo - > panel_info . xres )
mode - > xres = rinfo - > panel_info . xres ;
if ( mode - > yres > rinfo - > panel_info . yres )
mode - > yres = rinfo - > panel_info . yres ;
newmode - > fp_horz_stretch = ( ( ( rinfo - > panel_info . xres / 8 ) - 1 )
< < HORZ_PANEL_SHIFT ) ;
newmode - > fp_vert_stretch = ( ( rinfo - > panel_info . yres - 1 )
< < VERT_PANEL_SHIFT ) ;
if ( mode - > xres ! = rinfo - > panel_info . xres ) {
hRatio = round_div ( mode - > xres * HORZ_STRETCH_RATIO_MAX ,
rinfo - > panel_info . xres ) ;
newmode - > fp_horz_stretch = ( ( ( ( ( unsigned long ) hRatio ) & HORZ_STRETCH_RATIO_MASK ) ) |
( newmode - > fp_horz_stretch &
( HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
HORZ_AUTO_RATIO_INC ) ) ) ;
newmode - > fp_horz_stretch | = ( HORZ_STRETCH_BLEND |
HORZ_STRETCH_ENABLE ) ;
use_rmx = 1 ;
}
newmode - > fp_horz_stretch & = ~ HORZ_AUTO_RATIO ;
if ( mode - > yres ! = rinfo - > panel_info . yres ) {
vRatio = round_div ( mode - > yres * VERT_STRETCH_RATIO_MAX ,
rinfo - > panel_info . yres ) ;
newmode - > fp_vert_stretch = ( ( ( ( ( unsigned long ) vRatio ) & VERT_STRETCH_RATIO_MASK ) ) |
( newmode - > fp_vert_stretch &
( VERT_PANEL_SIZE | VERT_STRETCH_RESERVED ) ) ) ;
newmode - > fp_vert_stretch | = ( VERT_STRETCH_BLEND |
VERT_STRETCH_ENABLE ) ;
use_rmx = 1 ;
}
newmode - > fp_vert_stretch & = ~ VERT_AUTO_RATIO_EN ;
newmode - > fp_gen_cntl = ( rinfo - > init_state . fp_gen_cntl & ( u32 )
~ ( FP_SEL_CRTC2 |
FP_RMX_HVSYNC_CONTROL_EN |
FP_DFP_SYNC_SEL |
FP_CRT_SYNC_SEL |
FP_CRTC_LOCK_8DOT |
FP_USE_SHADOW_EN |
FP_CRTC_USE_SHADOW_VEND |
FP_CRT_SYNC_ALT ) ) ;
newmode - > fp_gen_cntl | = ( FP_CRTC_DONT_SHADOW_VPAR |
FP_CRTC_DONT_SHADOW_HEND |
FP_PANEL_FORMAT ) ;
if ( IS_R300_VARIANT ( rinfo ) | |
( rinfo - > family = = CHIP_FAMILY_R200 ) ) {
newmode - > fp_gen_cntl & = ~ R200_FP_SOURCE_SEL_MASK ;
if ( use_rmx )
newmode - > fp_gen_cntl | = R200_FP_SOURCE_SEL_RMX ;
else
newmode - > fp_gen_cntl | = R200_FP_SOURCE_SEL_CRTC1 ;
} else
newmode - > fp_gen_cntl | = FP_SEL_CRTC1 ;
newmode - > lvds_gen_cntl = rinfo - > init_state . lvds_gen_cntl ;
newmode - > lvds_pll_cntl = rinfo - > init_state . lvds_pll_cntl ;
newmode - > tmds_crc = rinfo - > init_state . tmds_crc ;
newmode - > tmds_transmitter_cntl = rinfo - > init_state . tmds_transmitter_cntl ;
if ( primary_mon = = MT_LCD ) {
newmode - > lvds_gen_cntl | = ( LVDS_ON | LVDS_BLON ) ;
newmode - > fp_gen_cntl & = ~ ( FP_FPON | FP_TMDS_EN ) ;
} else {
/* DFP */
newmode - > fp_gen_cntl | = ( FP_FPON | FP_TMDS_EN ) ;
newmode - > tmds_transmitter_cntl & = ~ ( TMDS_PLLRST ) ;
/* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
if ( IS_R300_VARIANT ( rinfo ) | |
( rinfo - > family = = CHIP_FAMILY_R200 ) | | ! rinfo - > has_CRTC2 )
newmode - > tmds_transmitter_cntl & = ~ TMDS_PLL_EN ;
else
newmode - > tmds_transmitter_cntl | = TMDS_PLL_EN ;
newmode - > crtc_ext_cntl & = ~ CRTC_CRT_ON ;
}
newmode - > fp_crtc_h_total_disp = ( ( ( rinfo - > panel_info . hblank / 8 ) & 0x3ff ) |
( ( ( mode - > xres / 8 ) - 1 ) < < 16 ) ) ;
newmode - > fp_crtc_v_total_disp = ( rinfo - > panel_info . vblank & 0xffff ) |
( ( mode - > yres - 1 ) < < 16 ) ;
newmode - > fp_h_sync_strt_wid = ( ( rinfo - > panel_info . hOver_plus & 0x1fff ) |
( hsync_wid < < 16 ) | ( h_sync_pol < < 23 ) ) ;
newmode - > fp_v_sync_strt_wid = ( ( rinfo - > panel_info . vOver_plus & 0xfff ) |
( vsync_wid < < 16 ) | ( v_sync_pol < < 23 ) ) ;
}
/* do it! */
if ( ! rinfo - > asleep ) {
memcpy ( & rinfo - > state , newmode , sizeof ( * newmode ) ) ;
radeon_write_mode ( rinfo , newmode , 0 ) ;
/* (re)initialize the engine */
if ( ! ( info - > flags & FBINFO_HWACCEL_DISABLED ) )
radeonfb_engine_init ( rinfo ) ;
}
/* Update fix */
if ( ! ( info - > flags & FBINFO_HWACCEL_DISABLED ) )
info - > fix . line_length = rinfo - > pitch * 64 ;
else
info - > fix . line_length = mode - > xres_virtual
* ( ( mode - > bits_per_pixel + 1 ) / 8 ) ;
info - > fix . visual = rinfo - > depth = = 8 ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR ;
# ifdef CONFIG_BOOTX_TEXT
/* Update debug text engine */
btext_update_display ( rinfo - > fb_base_phys , mode - > xres , mode - > yres ,
rinfo - > depth , info - > fix . line_length ) ;
# endif
kfree ( newmode ) ;
return 0 ;
}
static struct fb_ops radeonfb_ops = {
. owner = THIS_MODULE ,
. fb_check_var = radeonfb_check_var ,
. fb_set_par = radeonfb_set_par ,
. fb_setcolreg = radeonfb_setcolreg ,
2005-05-01 08:59:22 -07:00
. fb_setcmap = radeonfb_setcmap ,
2005-04-16 15:20:36 -07:00
. fb_pan_display = radeonfb_pan_display ,
. fb_blank = radeonfb_blank ,
. fb_ioctl = radeonfb_ioctl ,
. fb_sync = radeonfb_sync ,
. fb_fillrect = radeonfb_fillrect ,
. fb_copyarea = radeonfb_copyarea ,
. fb_imageblit = radeonfb_imageblit ,
} ;
static int __devinit radeon_set_fbinfo ( struct radeonfb_info * rinfo )
{
struct fb_info * info = rinfo - > info ;
info - > par = rinfo ;
info - > pseudo_palette = rinfo - > pseudo_palette ;
info - > flags = FBINFO_DEFAULT
| FBINFO_HWACCEL_COPYAREA
| FBINFO_HWACCEL_FILLRECT
| FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN ;
info - > fbops = & radeonfb_ops ;
info - > screen_base = rinfo - > fb_base ;
info - > screen_size = rinfo - > mapped_vram ;
/* Fill fix common fields */
strlcpy ( info - > fix . id , rinfo - > name , sizeof ( info - > fix . id ) ) ;
info - > fix . smem_start = rinfo - > fb_base_phys ;
info - > fix . smem_len = rinfo - > video_ram ;
info - > fix . type = FB_TYPE_PACKED_PIXELS ;
info - > fix . visual = FB_VISUAL_PSEUDOCOLOR ;
info - > fix . xpanstep = 8 ;
info - > fix . ypanstep = 1 ;
info - > fix . ywrapstep = 0 ;
info - > fix . type_aux = 0 ;
info - > fix . mmio_start = rinfo - > mmio_base_phys ;
info - > fix . mmio_len = RADEON_REGSIZE ;
info - > fix . accel = FB_ACCEL_ATI_RADEON ;
fb_alloc_cmap ( & info - > cmap , 256 , 0 ) ;
if ( noaccel )
info - > flags | = FBINFO_HWACCEL_DISABLED ;
return 0 ;
}
/*
* This reconfigure the card ' s internal memory map . In theory , we ' d like
* to setup the card ' s memory at the same address as it ' s PCI bus address ,
* and the AGP aperture right after that so that system RAM on 32 bits
* machines at least , is directly accessible . However , doing so would
* conflict with the current XFree drivers . . .
* Ultimately , I hope XFree , GATOS and ATI binary drivers will all agree
* on the proper way to set this up and duplicate this here . In the meantime ,
* I put the card ' s memory at 0 in card space and AGP at some random high
* local ( 0xe0000000 for now ) that will be changed by XFree / DRI anyway
*/
# ifdef CONFIG_PPC_OF
# undef SET_MC_FB_FROM_APERTURE
static void fixup_memory_mappings ( struct radeonfb_info * rinfo )
{
u32 save_crtc_gen_cntl , save_crtc2_gen_cntl = 0 ;
u32 save_crtc_ext_cntl ;
u32 aper_base , aper_size ;
u32 agp_base ;
/* First, we disable display to avoid interfering */
if ( rinfo - > has_CRTC2 ) {
save_crtc2_gen_cntl = INREG ( CRTC2_GEN_CNTL ) ;
OUTREG ( CRTC2_GEN_CNTL , save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B ) ;
}
save_crtc_gen_cntl = INREG ( CRTC_GEN_CNTL ) ;
save_crtc_ext_cntl = INREG ( CRTC_EXT_CNTL ) ;
OUTREG ( CRTC_EXT_CNTL , save_crtc_ext_cntl | CRTC_DISPLAY_DIS ) ;
OUTREG ( CRTC_GEN_CNTL , save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B ) ;
mdelay ( 100 ) ;
aper_base = INREG ( CONFIG_APER_0_BASE ) ;
aper_size = INREG ( CONFIG_APER_SIZE ) ;
# ifdef SET_MC_FB_FROM_APERTURE
/* Set framebuffer to be at the same address as set in PCI BAR */
OUTREG ( MC_FB_LOCATION ,
( ( aper_base + aper_size - 1 ) & 0xffff0000 ) | ( aper_base > > 16 ) ) ;
rinfo - > fb_local_base = aper_base ;
# else
OUTREG ( MC_FB_LOCATION , 0x7fff0000 ) ;
rinfo - > fb_local_base = 0 ;
# endif
agp_base = aper_base + aper_size ;
if ( agp_base & 0xf0000000 )
agp_base = ( aper_base | 0x0fffffff ) + 1 ;
/* Set AGP to be just after the framebuffer on a 256Mb boundary. This
* assumes the FB isn ' t mapped to 0xf0000000 or above , but this is
* always the case on PPCs afaik .
*/
# ifdef SET_MC_FB_FROM_APERTURE
OUTREG ( MC_AGP_LOCATION , 0xffff0000 | ( agp_base > > 16 ) ) ;
# else
OUTREG ( MC_AGP_LOCATION , 0xffffe000 ) ;
# endif
/* Fixup the display base addresses & engine offsets while we
* are at it as well
*/
# ifdef SET_MC_FB_FROM_APERTURE
OUTREG ( DISPLAY_BASE_ADDR , aper_base ) ;
if ( rinfo - > has_CRTC2 )
OUTREG ( CRTC2_DISPLAY_BASE_ADDR , aper_base ) ;
OUTREG ( OV0_BASE_ADDR , aper_base ) ;
# else
OUTREG ( DISPLAY_BASE_ADDR , 0 ) ;
if ( rinfo - > has_CRTC2 )
OUTREG ( CRTC2_DISPLAY_BASE_ADDR , 0 ) ;
OUTREG ( OV0_BASE_ADDR , 0 ) ;
# endif
mdelay ( 100 ) ;
/* Restore display settings */
OUTREG ( CRTC_GEN_CNTL , save_crtc_gen_cntl ) ;
OUTREG ( CRTC_EXT_CNTL , save_crtc_ext_cntl ) ;
if ( rinfo - > has_CRTC2 )
OUTREG ( CRTC2_GEN_CNTL , save_crtc2_gen_cntl ) ;
RTRACE ( " aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x \n " ,
aper_base ,
( ( aper_base + aper_size - 1 ) & 0xffff0000 ) | ( aper_base > > 16 ) ,
0xffff0000 | ( agp_base > > 16 ) ) ;
}
# endif /* CONFIG_PPC_OF */
static void radeon_identify_vram ( struct radeonfb_info * rinfo )
{
u32 tmp ;
/* framebuffer size */
if ( ( rinfo - > family = = CHIP_FAMILY_RS100 ) | |
( rinfo - > family = = CHIP_FAMILY_RS200 ) | |
2007-05-08 00:37:59 -07:00
( rinfo - > family = = CHIP_FAMILY_RS300 ) | |
( rinfo - > family = = CHIP_FAMILY_RS480 ) ) {
2005-04-16 15:20:36 -07:00
u32 tom = INREG ( NB_TOM ) ;
tmp = ( ( ( ( tom > > 16 ) - ( tom & 0xffff ) + 1 ) < < 6 ) * 1024 ) ;
radeon_fifo_wait ( 6 ) ;
OUTREG ( MC_FB_LOCATION , tom ) ;
OUTREG ( DISPLAY_BASE_ADDR , ( tom & 0xffff ) < < 16 ) ;
OUTREG ( CRTC2_DISPLAY_BASE_ADDR , ( tom & 0xffff ) < < 16 ) ;
OUTREG ( OV0_BASE_ADDR , ( tom & 0xffff ) < < 16 ) ;
/* This is supposed to fix the crtc2 noise problem. */
OUTREG ( GRPH2_BUFFER_CNTL , INREG ( GRPH2_BUFFER_CNTL ) & ~ 0x7f0000 ) ;
if ( ( rinfo - > family = = CHIP_FAMILY_RS100 ) | |
( rinfo - > family = = CHIP_FAMILY_RS200 ) ) {
/* This is to workaround the asic bug for RMX, some versions
of BIOS dosen ' t have this register initialized correctly .
*/
OUTREGP ( CRTC_MORE_CNTL , CRTC_H_CUTOFF_ACTIVE_EN ,
~ CRTC_H_CUTOFF_ACTIVE_EN ) ;
}
} else {
tmp = INREG ( CONFIG_MEMSIZE ) ;
}
/* mem size is bits [28:0], mask off the rest */
rinfo - > video_ram = tmp & CONFIG_MEMSIZE_MASK ;
/*
* Hack to get around some busted production M6 ' s
* reporting no ram
*/
if ( rinfo - > video_ram = = 0 ) {
switch ( rinfo - > pdev - > device ) {
case PCI_CHIP_RADEON_LY :
case PCI_CHIP_RADEON_LZ :
rinfo - > video_ram = 8192 * 1024 ;
break ;
default :
break ;
}
}
/*
* Now try to identify VRAM type
*/
if ( rinfo - > is_IGP | | ( rinfo - > family > = CHIP_FAMILY_R300 ) | |
( INREG ( MEM_SDRAM_MODE_REG ) & ( 1 < < 30 ) ) )
rinfo - > vram_ddr = 1 ;
else
rinfo - > vram_ddr = 0 ;
tmp = INREG ( MEM_CNTL ) ;
if ( IS_R300_VARIANT ( rinfo ) ) {
tmp & = R300_MEM_NUM_CHANNELS_MASK ;
switch ( tmp ) {
case 0 : rinfo - > vram_width = 64 ; break ;
case 1 : rinfo - > vram_width = 128 ; break ;
case 2 : rinfo - > vram_width = 256 ; break ;
default : rinfo - > vram_width = 128 ; break ;
}
} else if ( ( rinfo - > family = = CHIP_FAMILY_RV100 ) | |
( rinfo - > family = = CHIP_FAMILY_RS100 ) | |
( rinfo - > family = = CHIP_FAMILY_RS200 ) ) {
if ( tmp & RV100_MEM_HALF_MODE )
rinfo - > vram_width = 32 ;
else
rinfo - > vram_width = 64 ;
} else {
if ( tmp & MEM_NUM_CHANNELS_MASK )
rinfo - > vram_width = 128 ;
else
rinfo - > vram_width = 64 ;
}
/* This may not be correct, as some cards can have half of channel disabled
* ToDo : identify these cases
*/
RTRACE ( " radeonfb (%s): Found %ldk of %s %d bits wide videoram \n " ,
pci_name ( rinfo - > pdev ) ,
rinfo - > video_ram / 1024 ,
rinfo - > vram_ddr ? " DDR " : " SDRAM " ,
rinfo - > vram_width ) ;
}
/*
* Sysfs
*/
static ssize_t radeon_show_one_edid ( char * buf , loff_t off , size_t count , const u8 * edid )
{
if ( off > EDID_LENGTH )
return 0 ;
if ( off + count > EDID_LENGTH )
count = EDID_LENGTH - off ;
memcpy ( buf , edid + off , count ) ;
return count ;
}
static ssize_t radeon_show_edid1 ( struct kobject * kobj , char * buf , loff_t off , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct pci_dev * pdev = to_pci_dev ( dev ) ;
struct fb_info * info = pci_get_drvdata ( pdev ) ;
struct radeonfb_info * rinfo = info - > par ;
return radeon_show_one_edid ( buf , off , count , rinfo - > mon1_EDID ) ;
}
static ssize_t radeon_show_edid2 ( struct kobject * kobj , char * buf , loff_t off , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct pci_dev * pdev = to_pci_dev ( dev ) ;
struct fb_info * info = pci_get_drvdata ( pdev ) ;
struct radeonfb_info * rinfo = info - > par ;
return radeon_show_one_edid ( buf , off , count , rinfo - > mon2_EDID ) ;
}
static struct bin_attribute edid1_attr = {
. attr = {
. name = " edid1 " ,
. owner = THIS_MODULE ,
. mode = 0444 ,
} ,
. size = EDID_LENGTH ,
. read = radeon_show_edid1 ,
} ;
static struct bin_attribute edid2_attr = {
. attr = {
. name = " edid2 " ,
. owner = THIS_MODULE ,
. mode = 0444 ,
} ,
. size = EDID_LENGTH ,
. read = radeon_show_edid2 ,
} ;
2006-04-18 22:22:10 -07:00
static int __devinit radeonfb_pci_register ( struct pci_dev * pdev ,
2005-04-16 15:20:36 -07:00
const struct pci_device_id * ent )
{
struct fb_info * info ;
struct radeonfb_info * rinfo ;
int ret ;
RTRACE ( " radeonfb_pci_register BEGIN \n " ) ;
/* Enable device in PCI config */
ret = pci_enable_device ( pdev ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " radeonfb (%s): Cannot enable PCI device \n " ,
pci_name ( pdev ) ) ;
goto err_out ;
}
info = framebuffer_alloc ( sizeof ( struct radeonfb_info ) , & pdev - > dev ) ;
if ( ! info ) {
printk ( KERN_ERR " radeonfb (%s): could not allocate memory \n " ,
pci_name ( pdev ) ) ;
ret = - ENOMEM ;
goto err_disable ;
}
rinfo = info - > par ;
rinfo - > info = info ;
rinfo - > pdev = pdev ;
spin_lock_init ( & rinfo - > reg_lock ) ;
init_timer ( & rinfo - > lvds_timer ) ;
rinfo - > lvds_timer . function = radeon_lvds_timer_func ;
rinfo - > lvds_timer . data = ( unsigned long ) rinfo ;
strcpy ( rinfo - > name , " ATI Radeon XX " ) ;
rinfo - > name [ 11 ] = ent - > device > > 8 ;
rinfo - > name [ 12 ] = ent - > device & 0xFF ;
rinfo - > family = ent - > driver_data & CHIP_FAMILY_MASK ;
rinfo - > chipset = pdev - > device ;
rinfo - > has_CRTC2 = ( ent - > driver_data & CHIP_HAS_CRTC2 ) ! = 0 ;
rinfo - > is_mobility = ( ent - > driver_data & CHIP_IS_MOBILITY ) ! = 0 ;
rinfo - > is_IGP = ( ent - > driver_data & CHIP_IS_IGP ) ! = 0 ;
/* Set base addrs */
rinfo - > fb_base_phys = pci_resource_start ( pdev , 0 ) ;
rinfo - > mmio_base_phys = pci_resource_start ( pdev , 2 ) ;
/* request the mem regions */
2005-09-09 13:04:59 -07:00
ret = pci_request_region ( pdev , 0 , " radeonfb framebuffer " ) ;
2005-04-16 15:20:36 -07:00
if ( ret < 0 ) {
2005-09-09 13:04:59 -07:00
printk ( KERN_ERR " radeonfb (%s): cannot request region 0. \n " ,
pci_name ( rinfo - > pdev ) ) ;
2005-04-16 15:20:36 -07:00
goto err_release_fb ;
}
2005-09-09 13:04:59 -07:00
ret = pci_request_region ( pdev , 2 , " radeonfb mmio " ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " radeonfb (%s): cannot request region 2. \n " ,
pci_name ( rinfo - > pdev ) ) ;
goto err_release_pci0 ;
}
2005-04-16 15:20:36 -07:00
/* map the regions */
rinfo - > mmio_base = ioremap ( rinfo - > mmio_base_phys , RADEON_REGSIZE ) ;
if ( ! rinfo - > mmio_base ) {
2005-09-09 13:04:59 -07:00
printk ( KERN_ERR " radeonfb (%s): cannot map MMIO \n " ,
pci_name ( rinfo - > pdev ) ) ;
2005-04-16 15:20:36 -07:00
ret = - EIO ;
2005-09-09 13:04:59 -07:00
goto err_release_pci2 ;
2005-04-16 15:20:36 -07:00
}
rinfo - > fb_local_base = INREG ( MC_FB_LOCATION ) < < 16 ;
/*
* Check for errata
*/
rinfo - > errata = 0 ;
if ( rinfo - > family = = CHIP_FAMILY_R300 & &
( INREG ( CONFIG_CNTL ) & CFG_ATI_REV_ID_MASK )
= = CFG_ATI_REV_A11 )
rinfo - > errata | = CHIP_ERRATA_R300_CG ;
if ( rinfo - > family = = CHIP_FAMILY_RV200 | |
rinfo - > family = = CHIP_FAMILY_RS200 )
rinfo - > errata | = CHIP_ERRATA_PLL_DUMMYREADS ;
if ( rinfo - > family = = CHIP_FAMILY_RV100 | |
rinfo - > family = = CHIP_FAMILY_RS100 | |
rinfo - > family = = CHIP_FAMILY_RS200 )
rinfo - > errata | = CHIP_ERRATA_PLL_DELAY ;
2007-03-29 01:33:46 -07:00
# if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
2005-04-16 15:20:36 -07:00
/* On PPC, we obtain the OF device-node pointer to the firmware
* data for this chip
*/
rinfo - > of_node = pci_device_to_OF_node ( pdev ) ;
if ( rinfo - > of_node = = NULL )
printk ( KERN_WARNING " radeonfb (%s): Cannot match card to OF node ! \n " ,
pci_name ( rinfo - > pdev ) ) ;
2007-03-29 01:33:46 -07:00
# endif /* CONFIG_PPC_OF || CONFIG_SPARC */
# ifdef CONFIG_PPC_OF
2005-04-16 15:20:36 -07:00
/* On PPC, the firmware sets up a memory mapping that tends
* to cause lockups when enabling the engine . We reconfigure
* the card internal memory mappings properly
*/
fixup_memory_mappings ( rinfo ) ;
# endif /* CONFIG_PPC_OF */
/* Get VRAM size and type */
radeon_identify_vram ( rinfo ) ;
rinfo - > mapped_vram = min_t ( unsigned long , MAX_MAPPED_VRAM , rinfo - > video_ram ) ;
do {
rinfo - > fb_base = ioremap ( rinfo - > fb_base_phys ,
rinfo - > mapped_vram ) ;
} while ( rinfo - > fb_base = = 0 & &
( ( rinfo - > mapped_vram / = 2 ) > = MIN_MAPPED_VRAM ) ) ;
2005-06-11 09:45:30 +10:00
if ( rinfo - > fb_base = = NULL ) {
printk ( KERN_ERR " radeonfb (%s): cannot map FB \n " ,
pci_name ( rinfo - > pdev ) ) ;
2005-04-16 15:20:36 -07:00
ret = - EIO ;
goto err_unmap_rom ;
}
RTRACE ( " radeonfb (%s): mapped %ldk videoram \n " , pci_name ( rinfo - > pdev ) ,
rinfo - > mapped_vram / 1024 ) ;
/*
2006-01-03 13:27:11 +01:00
* Map the BIOS ROM if any and retrieve PLL parameters from
2005-04-16 15:20:36 -07:00
* the BIOS . We skip that on mobility chips as the real panel
* values we need aren ' t in the ROM but in the BIOS image in
* memory . This is definitely not the best meacnism though ,
* we really need the arch code to tell us which is the " primary "
* video adapter to use the memory image ( or better , the arch
* should provide us a copy of the BIOS image to shield us from
* archs who would store that elsewhere and / or could initialize
* more than one adapter during boot ) .
*/
if ( ! rinfo - > is_mobility )
radeon_map_ROM ( rinfo , pdev ) ;
/*
* On x86 , the primary display on laptop may have it ' s BIOS
* ROM elsewhere , try to locate it at the legacy memory hole .
* We probably need to make sure this is the primary display ,
* but that is difficult without some arch support .
*/
# ifdef CONFIG_X86
if ( rinfo - > bios_seg = = NULL )
radeon_find_mem_vbios ( rinfo ) ;
# endif
/* If both above failed, try the BIOS ROM again for mobility
* chips
*/
if ( rinfo - > bios_seg = = NULL & & rinfo - > is_mobility )
radeon_map_ROM ( rinfo , pdev ) ;
/* Get informations about the board's PLL */
radeon_get_pllinfo ( rinfo ) ;
# ifdef CONFIG_FB_RADEON_I2C
/* Register I2C bus */
radeon_create_i2c_busses ( rinfo ) ;
# endif
/* set all the vital stuff */
radeon_set_fbinfo ( rinfo ) ;
/* Probe screen types */
radeon_probe_screens ( rinfo , monitor_layout , ignore_edid ) ;
/* Build mode list, check out panel native model */
radeon_check_modes ( rinfo , mode_option ) ;
/* Register some sysfs stuff (should be done better) */
if ( rinfo - > mon1_EDID )
sysfs_create_bin_file ( & rinfo - > pdev - > dev . kobj , & edid1_attr ) ;
if ( rinfo - > mon2_EDID )
sysfs_create_bin_file ( & rinfo - > pdev - > dev . kobj , & edid2_attr ) ;
/* save current mode regs before we switch into the new one
* so we can restore this upon __exit
*/
radeon_save_state ( rinfo , & rinfo - > init_state ) ;
memcpy ( & rinfo - > state , & rinfo - > init_state , sizeof ( struct radeon_regs ) ) ;
/* Setup Power Management capabilities */
if ( default_dynclk < - 1 ) {
/* -2 is special: means ON on mobility chips and do not
* change on others
*/
2006-07-30 03:04:18 -07:00
radeonfb_pm_init ( rinfo , rinfo - > is_mobility ? 1 : - 1 , ignore_devlist , force_sleep ) ;
2005-04-16 15:20:36 -07:00
} else
2006-07-30 03:04:18 -07:00
radeonfb_pm_init ( rinfo , default_dynclk , ignore_devlist , force_sleep ) ;
2005-04-16 15:20:36 -07:00
pci_set_drvdata ( pdev , info ) ;
/* Register with fbdev layer */
ret = register_framebuffer ( info ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " radeonfb (%s): could not register framebuffer \n " ,
pci_name ( rinfo - > pdev ) ) ;
goto err_unmap_fb ;
}
# ifdef CONFIG_MTRR
rinfo - > mtrr_hdl = nomtrr ? - 1 : mtrr_add ( rinfo - > fb_base_phys ,
rinfo - > video_ram ,
MTRR_TYPE_WRCOMB , 1 ) ;
# endif
2007-03-03 17:43:52 +00:00
if ( backlight )
radeonfb_bl_init ( rinfo ) ;
2005-04-16 15:20:36 -07:00
printk ( " radeonfb (%s): %s \n " , pci_name ( rinfo - > pdev ) , rinfo - > name ) ;
if ( rinfo - > bios_seg )
radeon_unmap_ROM ( rinfo , pdev ) ;
RTRACE ( " radeonfb_pci_register END \n " ) ;
return 0 ;
err_unmap_fb :
iounmap ( rinfo - > fb_base ) ;
err_unmap_rom :
kfree ( rinfo - > mon1_EDID ) ;
kfree ( rinfo - > mon2_EDID ) ;
if ( rinfo - > mon1_modedb )
fb_destroy_modedb ( rinfo - > mon1_modedb ) ;
fb_dealloc_cmap ( & info - > cmap ) ;
# ifdef CONFIG_FB_RADEON_I2C
radeon_delete_i2c_busses ( rinfo ) ;
# endif
if ( rinfo - > bios_seg )
radeon_unmap_ROM ( rinfo , pdev ) ;
iounmap ( rinfo - > mmio_base ) ;
2005-09-09 13:04:59 -07:00
err_release_pci2 :
pci_release_region ( pdev , 2 ) ;
err_release_pci0 :
pci_release_region ( pdev , 0 ) ;
2005-04-16 15:20:36 -07:00
err_release_fb :
2005-09-09 13:04:59 -07:00
framebuffer_release ( info ) ;
2005-04-16 15:20:36 -07:00
err_disable :
err_out :
return ret ;
}
static void __devexit radeonfb_pci_unregister ( struct pci_dev * pdev )
{
struct fb_info * info = pci_get_drvdata ( pdev ) ;
struct radeonfb_info * rinfo = info - > par ;
if ( ! rinfo )
return ;
2006-06-25 05:47:08 -07:00
2005-04-16 15:20:36 -07:00
radeonfb_pm_exit ( rinfo ) ;
2005-07-27 11:46:05 -07:00
if ( rinfo - > mon1_EDID )
sysfs_remove_bin_file ( & rinfo - > pdev - > dev . kobj , & edid1_attr ) ;
if ( rinfo - > mon2_EDID )
sysfs_remove_bin_file ( & rinfo - > pdev - > dev . kobj , & edid2_attr ) ;
2005-04-16 15:20:36 -07:00
#if 0
/* restore original state
*
* Doesn ' t quite work yet , I suspect if we come from a legacy
* VGA mode ( or worse , text mode ) , we need to do some VGA black
* magic here that I know nothing about . - - BenH
*/
radeon_write_mode ( rinfo , & rinfo - > init_state , 1 ) ;
# endif
del_timer_sync ( & rinfo - > lvds_timer ) ;
# ifdef CONFIG_MTRR
if ( rinfo - > mtrr_hdl > = 0 )
mtrr_del ( rinfo - > mtrr_hdl , 0 , 0 ) ;
# endif
unregister_framebuffer ( info ) ;
2007-02-10 14:10:33 +00:00
radeonfb_bl_exit ( rinfo ) ;
2005-04-16 15:20:36 -07:00
iounmap ( rinfo - > mmio_base ) ;
iounmap ( rinfo - > fb_base ) ;
2005-09-09 13:04:59 -07:00
pci_release_region ( pdev , 2 ) ;
pci_release_region ( pdev , 0 ) ;
2005-04-16 15:20:36 -07:00
kfree ( rinfo - > mon1_EDID ) ;
kfree ( rinfo - > mon2_EDID ) ;
if ( rinfo - > mon1_modedb )
fb_destroy_modedb ( rinfo - > mon1_modedb ) ;
# ifdef CONFIG_FB_RADEON_I2C
radeon_delete_i2c_busses ( rinfo ) ;
# endif
fb_dealloc_cmap ( & info - > cmap ) ;
framebuffer_release ( info ) ;
}
static struct pci_driver radeonfb_driver = {
. name = " radeonfb " ,
. id_table = radeonfb_pci_table ,
. probe = radeonfb_pci_register ,
. remove = __devexit_p ( radeonfb_pci_unregister ) ,
# ifdef CONFIG_PM
. suspend = radeonfb_pci_suspend ,
. resume = radeonfb_pci_resume ,
# endif /* CONFIG_PM */
} ;
# ifndef MODULE
static int __init radeonfb_setup ( char * options )
{
char * this_opt ;
if ( ! options | | ! * options )
return 0 ;
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
if ( ! * this_opt )
continue ;
if ( ! strncmp ( this_opt , " noaccel " , 7 ) ) {
noaccel = 1 ;
} else if ( ! strncmp ( this_opt , " mirror " , 6 ) ) {
mirror = 1 ;
} else if ( ! strncmp ( this_opt , " force_dfp " , 9 ) ) {
force_dfp = 1 ;
} else if ( ! strncmp ( this_opt , " panel_yres: " , 11 ) ) {
panel_yres = simple_strtoul ( ( this_opt + 11 ) , NULL , 0 ) ;
2007-03-03 17:43:52 +00:00
} else if ( ! strncmp ( this_opt , " backlight: " , 10 ) ) {
backlight = simple_strtoul ( this_opt + 10 , NULL , 0 ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_MTRR
} else if ( ! strncmp ( this_opt , " nomtrr " , 6 ) ) {
nomtrr = 1 ;
# endif
} else if ( ! strncmp ( this_opt , " nomodeset " , 9 ) ) {
nomodeset = 1 ;
} else if ( ! strncmp ( this_opt , " force_measure_pll " , 17 ) ) {
force_measure_pll = 1 ;
} else if ( ! strncmp ( this_opt , " ignore_edid " , 11 ) ) {
ignore_edid = 1 ;
2006-07-30 03:04:18 -07:00
# if defined(CONFIG_PM) && defined(CONFIG_X86)
} else if ( ! strncmp ( this_opt , " force_sleep " , 11 ) ) {
force_sleep = 1 ;
} else if ( ! strncmp ( this_opt , " ignore_devlist " , 14 ) ) {
ignore_devlist = 1 ;
# endif
2005-04-16 15:20:36 -07:00
} else
mode_option = this_opt ;
}
return 0 ;
}
# endif /* MODULE */
static int __init radeonfb_init ( void )
{
# ifndef MODULE
char * option = NULL ;
if ( fb_get_options ( " radeonfb " , & option ) )
return - ENODEV ;
radeonfb_setup ( option ) ;
# endif
return pci_register_driver ( & radeonfb_driver ) ;
}
static void __exit radeonfb_exit ( void )
{
pci_unregister_driver ( & radeonfb_driver ) ;
}
module_init ( radeonfb_init ) ;
module_exit ( radeonfb_exit ) ;
MODULE_AUTHOR ( " Ani Joshi " ) ;
MODULE_DESCRIPTION ( " framebuffer driver for ATI Radeon chipset " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( noaccel , bool , 0 ) ;
module_param ( default_dynclk , int , 0 ) ;
MODULE_PARM_DESC ( default_dynclk , " int: -2=enable on mobility only,-1=do not change,0=off,1=on " ) ;
MODULE_PARM_DESC ( noaccel , " bool: disable acceleration " ) ;
module_param ( nomodeset , bool , 0 ) ;
MODULE_PARM_DESC ( nomodeset , " bool: disable actual setting of video mode " ) ;
module_param ( mirror , bool , 0 ) ;
MODULE_PARM_DESC ( mirror , " bool: mirror the display to both monitors " ) ;
module_param ( force_dfp , bool , 0 ) ;
MODULE_PARM_DESC ( force_dfp , " bool: force display to dfp " ) ;
module_param ( ignore_edid , bool , 0 ) ;
MODULE_PARM_DESC ( ignore_edid , " bool: Ignore EDID data when doing DDC probe " ) ;
module_param ( monitor_layout , charp , 0 ) ;
MODULE_PARM_DESC ( monitor_layout , " Specify monitor mapping (like XFree86) " ) ;
module_param ( force_measure_pll , bool , 0 ) ;
MODULE_PARM_DESC ( force_measure_pll , " Force measurement of PLL (debug) " ) ;
# ifdef CONFIG_MTRR
module_param ( nomtrr , bool , 0 ) ;
MODULE_PARM_DESC ( nomtrr , " bool: disable use of MTRR registers " ) ;
# endif
module_param ( panel_yres , int , 0 ) ;
MODULE_PARM_DESC ( panel_yres , " int: set panel yres " ) ;
module_param ( mode_option , charp , 0 ) ;
MODULE_PARM_DESC ( mode_option , " Specify resolution as \" <xres>x<yres>[-<bpp>][@<refresh>] \" " ) ;
2006-07-30 03:04:18 -07:00
# if defined(CONFIG_PM) && defined(CONFIG_X86)
module_param ( force_sleep , bool , 0 ) ;
MODULE_PARM_DESC ( force_sleep , " bool: force D2 sleep mode on all hardware " ) ;
module_param ( ignore_devlist , bool , 0 ) ;
MODULE_PARM_DESC ( ignore_devlist , " bool: ignore workarounds for bugs in specific laptops " ) ;
# endif