Patch by Euan Kirkhope:

* New "ATOM" BIOS Support for radeons X-series
* This also removes scanning for the BIOS signature for other cards


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20272 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-03-01 09:05:12 +00:00
parent 8841d8bcd1
commit 300bef5821
2 changed files with 168 additions and 107 deletions

View File

@ -8,4 +8,4 @@
*/
// current version
#define RADEON_DRIVER_VERSION "Version: 5.1.1.1"
#define RADEON_DRIVER_VERSION "Version: 5.1.2.1"

View File

@ -27,32 +27,17 @@
#include <stdio.h>
#include <string.h>
static const char ati_rom_sig[] = "761295520";
static const char *radeon_sig[] = {
"RADEON", // r100
"RV100", // rv100
"U1", // rs100 (IGP320M)
"M6", // mobile version of r100
// probably an M6P;
// anyway - this is the card I wrote this driver for!
// (perhaps ATI tries to make the card incompatible to standard drivers)
"P6",
"RV200", // rv200
"M7", // m7
"RG6", // r200 (according to spec)
"RS200", // rs200
"R200", // r200 (8500 LE)
"R200AGP", // Fire GL E1
"M9" // guess: m9
"RV250", // rv250 R9100
"V280", // RV280 R9200
"R300", // R300 R9500 / R9700
"R350", // R350 R9800
"R360", // R360 R9800 XT
"V350", // RV350 R9600
"V360", // RV350 R9600 XT :guess
};
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
#define RADEON_BIOS8(v) (di->rom.rom_ptr[v])
#define RADEON_BIOS16(v) ((di->rom.rom_ptr[v]) | \
(di->rom.rom_ptr[(v) + 1] << 8))
#define RADEON_BIOS32(v) ((di->rom.rom_ptr[v]) | \
(di->rom.rom_ptr[(v) + 1] << 8) \
(di->rom.rom_ptr[(v) + 2] << 16) \
(di->rom.rom_ptr[(v) + 3] << 24))
static const char ati_rom_sig[] = "761295520";
// find address of ROM;
// this code is really nasty as maintaining the radeon signatures
@ -70,7 +55,7 @@ static char *Radeon_FindRom( rom_info *ri )
uint32 segstart;
uint8 *rom_base;
char *rom;
int i,j;
int i;
for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) {
bool found = false;
@ -98,24 +83,8 @@ static char *Radeon_FindRom( rom_info *ri )
if( !found )
continue;
// find signature of card
found = false;
for( i = 0; i < 512; i++ ) {
for( j = 0; j < sizeof( radeon_sig ) / sizeof( radeon_sig[0] ); j++ ) {
if( radeon_sig[j][0] == rom_base[i] ) {
if( strncmp( radeon_sig[j], rom_base + i, strlen( radeon_sig[j] )) == 0 ) {
SHOW_INFO( 2, "Signature: %s", radeon_sig[j] );
found = true;
break;
}
}
}
}
if( !found )
continue;
// EK don't bother looking for signiture now, due to lack of consistancy.
SHOW_INFO( 2, "found ROM @0x%lx", segstart );
return rom_base;
}
@ -130,22 +99,70 @@ static char *Radeon_FindRom( rom_info *ri )
static void Radeon_GetPLLInfo( device_info *di )
{
uint8 *bios_header;
uint8 *tmp;
PLL_BLOCK pll, *pll_info;
bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48);
pll_info = (PLL_BLOCK *)(di->rom.rom_ptr + *(uint16 *)(bios_header + 0x30));
memcpy( &pll, pll_info, sizeof( pll ));
// determine type of ROM
tmp = bios_header + 4;
if (( *tmp == 'A'
&& *(tmp+1) == 'T'
&& *(tmp+2) == 'O'
&& *(tmp+3) == 'M'
)
||
( *tmp == 'M'
&& *(tmp+1) == 'O'
&& *(tmp+2) == 'T'
&& *(tmp+3) == 'A'
))
{
int bios_header, master_data_start, pll_start;
di->is_atombios = true;
di->pll.xclk = (uint32)pll.XCLK;
di->pll.ref_freq = (uint32)pll.PCLK_ref_freq;
di->pll.ref_div = (uint32)pll.PCLK_ref_divider;
di->pll.min_pll_freq = pll.PCLK_min_freq;
di->pll.max_pll_freq = pll.PCLK_max_freq;
SHOW_INFO( 2, "ref_clk=%ld, ref_div=%ld, xclk=%ld, min_freq=%ld, max_freq=%ld from BIOS",
bios_header = RADEON_BIOS16(0x48);
master_data_start = RADEON_BIOS16(bios_header + 32);
pll_start = RADEON_BIOS16(master_data_start + 12);
di->pll.ref_div = 0;
di->pll.max_pll_freq = RADEON_BIOS16(pll_start + 32);
di->pll.xclk = RADEON_BIOS16(pll_start + 72);
di->pll.min_pll_freq = RADEON_BIOS16(pll_start + 78);
di->pll.ref_freq = RADEON_BIOS16(pll_start + 82);
SHOW_INFO( 2, "TESTING ref_clk=%ld, ref_div=%ld, xclk=%ld, min_freq=%ld, max_freq=%ld from ATOM Bios",
di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
di->pll.min_pll_freq, di->pll.max_pll_freq );
// Unused by beos driver so it appears...
// info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0;
// info->mclk = RADEON_BIOS32(pll_info_block + 12) / 100.0;
// if (info->sclk == 0) info->sclk = 200;
// if (info->mclk == 0) info->mclk = 200;
}
else
{
di->is_atombios = false;
memcpy( &pll, pll_info, sizeof( pll ));
di->pll.xclk = (uint32)pll.XCLK;
di->pll.ref_freq = (uint32)pll.PCLK_ref_freq;
di->pll.ref_div = (uint32)pll.PCLK_ref_divider;
di->pll.min_pll_freq = pll.PCLK_min_freq;
di->pll.max_pll_freq = pll.PCLK_max_freq;
SHOW_INFO( 2, "ref_clk=%ld, ref_div=%ld, xclk=%ld, min_freq=%ld, max_freq=%ld from Legacy BIOS",
di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
di->pll.min_pll_freq, di->pll.max_pll_freq );
}
}
/*
@ -247,74 +264,118 @@ static void Radeon_GetMonType( device_info *di )
// who knows which strange kind of combination is out there?)
static bool Radeon_GetBIOSDFPInfo( device_info *di )
{
uint8 *bios_header;
uint16 bios_header;
uint16 fpi_offset;
FPI_BLOCK fpi;
char panel_name[30];
int i;
bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48);
uint16 tmp;
fpi_offset = *(uint16 *)(bios_header + 0x40);
bios_header = RADEON_BIOS16( 0x48 );
if (di->is_atombios)
{
int master_data_start;
master_data_start = RADEON_BIOS16( bios_header + 32 );
tmp = RADEON_BIOS16( master_data_start + 16 );
if( tmp )
{
if( !fpi_offset ) {
di->fp_info.panel_pwr_delay = 200;
SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
return false;
}
di->fp_info.panel_xres = RADEON_BIOS16( tmp + 6 );
di->fp_info.panel_yres = RADEON_BIOS16( tmp + 10 );
di->fp_info.dot_clock = RADEON_BIOS16( tmp + 4 ) * 10;
di->fp_info.h_blank = RADEON_BIOS16( tmp + 8 );
di->fp_info.h_over_plus = RADEON_BIOS16( tmp + 14 );
di->fp_info.h_sync_width = RADEON_BIOS16( tmp + 16 );
di->fp_info.v_blank = RADEON_BIOS16( tmp + 12 );
di->fp_info.v_over_plus = RADEON_BIOS16( tmp + 18 );
di->fp_info.h_sync_width = RADEON_BIOS16( tmp + 20 );
di->fp_info.panel_pwr_delay = RADEON_BIOS16( tmp + 40 );
SHOW_INFO( 2, "Panel Info from ATOMBIOS:\n"
"XRes: %d, YRes: %d, DotClock: %d\n"
"HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
"VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n"
"PanelPowerDelay: %d\n",
di->fp_info.panel_xres, di->fp_info.panel_yres, di->fp_info.dot_clock,
di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width,
di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.h_sync_width,
di->fp_info.panel_pwr_delay );
}
else
{
di->fp_info.panel_pwr_delay = 200;
SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
return false;
}
} // is_atombios
else
{
fpi_offset = RADEON_BIOS16(bios_header + 0x40);
memcpy( &fpi, di->rom.rom_ptr + fpi_offset, sizeof( fpi ));
memcpy( panel_name, &fpi.name, sizeof( fpi.name ) );
panel_name[sizeof( fpi.name )] = 0;
SHOW_INFO( 2, "Panel ID string: %s", panel_name );
if( !fpi_offset ) {
di->fp_info.panel_pwr_delay = 200;
SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
return false;
}
di->fp_info.panel_xres = fpi.panel_xres;
di->fp_info.panel_yres = fpi.panel_yres;
SHOW_INFO( 2, "Panel Size from BIOS: %dx%d",
di->fp_info.panel_xres, di->fp_info.panel_yres);
memcpy( &fpi, di->rom.rom_ptr + fpi_offset, sizeof( fpi ));
di->fp_info.panel_pwr_delay = fpi.panel_pwr_delay;
if( di->fp_info.panel_pwr_delay > 2000 || di->fp_info.panel_pwr_delay < 0 )
di->fp_info.panel_pwr_delay = 2000;
di->fp_info.ref_div = fpi.ref_div;
di->fp_info.post_div = fpi.post_div;
di->fp_info.feedback_div = fpi.feedback_div;
di->fp_info.fixed_dividers =
di->fp_info.ref_div != 0 && di->fp_info.feedback_div > 3;
// there might be multiple supported resolutions stored;
// we are looking for native resolution
for( i = 0; i < 20; ++i ) {
uint16 fpi_timing_ofs;
FPI_TIMING_BLOCK fpi_timing;
memcpy( panel_name, &fpi.name, sizeof( fpi.name ) );
panel_name[sizeof( fpi.name )] = 0;
fpi_timing_ofs = fpi.fpi_timing_ofs[i];
SHOW_INFO( 2, "Panel ID string: %s", panel_name );
di->fp_info.panel_xres = fpi.panel_xres;
di->fp_info.panel_yres = fpi.panel_yres;
if( fpi_timing_ofs == 0 )
break;
SHOW_INFO( 2, "Panel Size from BIOS: %dx%d",
di->fp_info.panel_xres, di->fp_info.panel_yres);
memcpy( &fpi_timing, di->rom.rom_ptr + fpi_timing_ofs, sizeof( fpi_timing ));
if( fpi_timing.panel_xres != di->fp_info.panel_xres ||
fpi_timing.panel_yres != di->fp_info.panel_yres )
continue;
di->fp_info.panel_pwr_delay = fpi.panel_pwr_delay;
if( di->fp_info.panel_pwr_delay > 2000 || di->fp_info.panel_pwr_delay < 0 )
di->fp_info.panel_pwr_delay = 2000;
di->fp_info.ref_div = fpi.ref_div;
di->fp_info.post_div = fpi.post_div;
di->fp_info.feedback_div = fpi.feedback_div;
di->fp_info.fixed_dividers =
di->fp_info.ref_div != 0 && di->fp_info.feedback_div > 3;
di->fp_info.h_blank = (fpi_timing.h_total - fpi_timing.h_display) * 8;
// TBD: seems like upper four bits of hsync_start contain garbage
di->fp_info.h_over_plus = ((fpi_timing.h_sync_start & 0xfff) - fpi_timing.h_display - 1) * 8;
di->fp_info.h_sync_width = fpi_timing.h_sync_width * 8;
di->fp_info.v_blank = fpi_timing.v_total - fpi_timing.v_display;
di->fp_info.v_over_plus = (fpi_timing.v_sync & 0x7ff) - fpi_timing.v_display;
di->fp_info.v_sync_width = (fpi_timing.v_sync & 0xf800) >> 11;
di->fp_info.dot_clock = fpi_timing.dot_clock * 10;
return true;
}
// there might be multiple supported resolutions stored;
// we are looking for native resolution
for( i = 0; i < 20; ++i ) {
uint16 fpi_timing_ofs;
FPI_TIMING_BLOCK fpi_timing;
fpi_timing_ofs = fpi.fpi_timing_ofs[i];
if( fpi_timing_ofs == 0 )
break;
memcpy( &fpi_timing, di->rom.rom_ptr + fpi_timing_ofs, sizeof( fpi_timing ));
if( fpi_timing.panel_xres != di->fp_info.panel_xres ||
fpi_timing.panel_yres != di->fp_info.panel_yres )
continue;
di->fp_info.h_blank = (fpi_timing.h_total - fpi_timing.h_display) * 8;
// TBD: seems like upper four bits of hsync_start contain garbage
di->fp_info.h_over_plus = ((fpi_timing.h_sync_start & 0xfff) - fpi_timing.h_display - 1) * 8;
di->fp_info.h_sync_width = fpi_timing.h_sync_width * 8;
di->fp_info.v_blank = fpi_timing.v_total - fpi_timing.v_display;
di->fp_info.v_over_plus = (fpi_timing.v_sync & 0x7ff) - fpi_timing.v_display;
di->fp_info.v_sync_width = (fpi_timing.v_sync & 0xf800) >> 11;
di->fp_info.dot_clock = fpi_timing.dot_clock * 10;
return true;
}
} // not is_atombios
SHOW_ERROR0( 2, "Radeon: couldn't get Panel Timing from BIOS" );
return false;