#include "radeon_driver.h"
#include "mmio.h"
#include "bios_regs.h"
#include "config_regs.h"
#include "memcntrl_regs.h"
#include "buscntrl_regs.h"
#include "fp_regs.h"
#include "crtc_regs.h"
#include "ddc_regs.h"
#include "radeon_bios.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
#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";
static const tmds_pll_info default_tmds_pll[14][4] =
{
{{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},
{{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},
{{0, 0}, {0, 0}, {0, 0}, {0, 0}},
{{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},
{{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},
{{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},
{{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}},
{{0, 0}, {0, 0}, {0, 0}, {0, 0}},
{{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}},
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},
};
static uint8*
Radeon_FindRom(rom_info* ri)
{
uint32 segstart;
uint8 *rom_base;
size_t i;
for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) {
bool found = false;
rom_base = ri->bios_ptr + segstart - 0xc0000;
if( rom_base[0] != 0x55 || rom_base[1] != 0xaa )
continue;
found = false;
for( i = 0; i < 128 - strlen( ati_rom_sig ); i++ ) {
if( ati_rom_sig[0] == rom_base[i] ) {
if (strncmp(ati_rom_sig, (char*)(rom_base + i), strlen(ati_rom_sig)) == 0) {
found = true;
break;
}
}
}
if( !found )
continue;
SHOW_INFO( 2, "found ROM @0x%" B_PRIx32, segstart );
return rom_base;
}
SHOW_INFO0( 2, "no ROM found" );
return NULL;
}
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));
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;
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=%" B_PRIu32 ", ref_div=%" B_PRIu32 ", xclk=%" B_PRIu32 ", "
"min_freq=%" B_PRIu32 ", max_freq=%" B_PRIu32 " from ATOM Bios",
di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
di->pll.min_pll_freq, di->pll.max_pll_freq );
}
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=%" B_PRIu32 ", ref_div=%" B_PRIu32 ", xclk=%" B_PRIu32 ", "
"min_freq=%" B_PRIu32 ", max_freq=%" B_PRIu32 " from Legacy BIOS",
di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
di->pll.min_pll_freq, di->pll.max_pll_freq );
}
}
static bool Radeon_GetConnectorInfoFromBIOS ( device_info* di )
{
ptr_disp_entity ptr_entity = &di->routing;
int i = 0, j, tmp, tmp0=0, tmp1=0;
int bios_header, master_data_start;
bios_header = RADEON_BIOS16(0x48);
if (di->is_atombios)
{
master_data_start = RADEON_BIOS16( bios_header + 32 );
tmp = RADEON_BIOS16( master_data_start + 22);
if (tmp) {
int crtc = 0, id[2];
tmp1 = RADEON_BIOS16( tmp + 4 );
for (i=0; i<8; i++) {
if(tmp1 & (1<<i)) {
uint16 portinfo = RADEON_BIOS16( tmp + 6 + i * 2 );
if (crtc < 2) {
if ((i == 2) || (i == 6)) continue;
if ( crtc == 1 ) {
if ((( portinfo >> 8) & 0xf) == id[0] ) {
if (i == 3)
ptr_entity->port_info[0].tmds_type = tmds_int;
else if (i == 7)
ptr_entity->port_info[0].tmds_type = tmds_ext;
if (ptr_entity->port_info[0].dac_type == dac_unknown)
ptr_entity->port_info[0].dac_type = (portinfo & 0xf) - 1;
continue;
}
}
id[crtc] = (portinfo>>8) & 0xf;
ptr_entity->port_info[crtc].dac_type = (portinfo & 0xf) - 1;
ptr_entity->port_info[crtc].connector_type = (portinfo>>4) & 0xf;
if (i == 3)
ptr_entity->port_info[crtc].tmds_type = tmds_int;
else if (i == 7)
ptr_entity->port_info[crtc].tmds_type = tmds_ext;
tmp0 = RADEON_BIOS16( master_data_start + 24);
if( tmp0 && id[crtc] ) {
switch (RADEON_BIOS16(tmp0 + 4 + 27 * id[crtc]) * 4)
{
case RADEON_GPIO_MONID:
ptr_entity->port_info[crtc].ddc_type = ddc_monid;
break;
case RADEON_GPIO_DVI_DDC:
ptr_entity->port_info[crtc].ddc_type = ddc_dvi;
break;
case RADEON_GPIO_VGA_DDC:
ptr_entity->port_info[crtc].ddc_type = ddc_vga;
break;
case RADEON_GPIO_CRT2_DDC:
ptr_entity->port_info[crtc].ddc_type = ddc_crt2;
break;
default:
ptr_entity->port_info[crtc].ddc_type = ddc_none_detected;
break;
}
} else {
ptr_entity->port_info[crtc].ddc_type = ddc_none_detected;
}
crtc++;
} else {
for ( j = 0; j < 2; j++ ) {
if ((( portinfo >> 8 ) & 0xf ) == id[j] ) {
if ( i == 3 )
ptr_entity->port_info[j].tmds_type = tmds_int;
else if (i == 7)
ptr_entity->port_info[j].tmds_type = tmds_ext;
if ( ptr_entity->port_info[j].dac_type == dac_unknown )
ptr_entity->port_info[j].dac_type = ( portinfo & 0xf ) - 1;
}
}
}
}
}
for (i=0; i<2; i++) {
SHOW_INFO( 2, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d",
i, ptr_entity->port_info[i].ddc_type, ptr_entity->port_info[i].dac_type,
ptr_entity->port_info[i].tmds_type, ptr_entity->port_info[i].connector_type);
}
} else {
SHOW_INFO0( 4 , "No Device Info Table found!");
return FALSE;
}
} else {
int connector_found = 0;
if ((tmp = RADEON_BIOS16( bios_header + 0x50 ))) {
for ( i = 1; i < 4; i++ ) {
if (!(RADEON_BIOS16( tmp + i * 2 )))
break;
tmp0 = RADEON_BIOS16( tmp + i * 2 );
if ((( tmp0 >> 12 ) & 0x0f ) == 0 )
continue;
if (connector_found > 0) {
if (ptr_entity->port_info[tmp1].ddc_type == (( tmp0 >> 8 ) & 0x0f ))
continue;
}
tmp1 = (((( tmp0 >> 8 ) & 0xf ) == ddc_dvi ) || ( tmp1 == 1 )) ? 0 : 1;
ptr_entity->port_info[tmp1].ddc_type = (tmp0 >> 8) & 0x0f;
if (ptr_entity->port_info[tmp1].ddc_type > ddc_crt2)
ptr_entity->port_info[tmp1].ddc_type = ddc_none_detected;
ptr_entity->port_info[tmp1].dac_type = (tmp0 & 0x01) ? dac_tvdac : dac_primary;
ptr_entity->port_info[tmp1].connector_type = (tmp0 >> 12) & 0x0f;
if (ptr_entity->port_info[tmp1].connector_type > connector_unsupported)
ptr_entity->port_info[tmp1].connector_type = connector_unsupported;
ptr_entity->port_info[tmp1].tmds_type = ((tmp0 >> 4) & 0x01) ? tmds_ext : tmds_int;
if (((ptr_entity->port_info[tmp1].connector_type != connector_dvi_d) &&
(ptr_entity->port_info[tmp1].connector_type != connector_dvi_i)) &&
ptr_entity->port_info[tmp1].tmds_type == tmds_int)
ptr_entity->port_info[tmp1].tmds_type = tmds_unknown;
connector_found += (tmp1 + 1);
}
} else {
SHOW_INFO0(4, "No Connector Info Table found!");
return FALSE;
}
if (di->is_mobility)
{
if ((connector_found < 3) && (ptr_entity->port_info[tmp1].connector_type == connector_crt)) {
if (connector_found == 1) {
memcpy (&ptr_entity->port_info[1],
&ptr_entity->port_info[0],
sizeof (ptr_entity->port_info[0]));
}
ptr_entity->port_info[0].dac_type = dac_tvdac;
ptr_entity->port_info[0].tmds_type = tmds_unknown;
ptr_entity->port_info[0].ddc_type = ddc_none_detected;
ptr_entity->port_info[0].connector_type = connector_proprietary;
SHOW_INFO0( 4 , "lvds port is not in connector table, added in.");
if (connector_found == 0)
connector_found = 1;
else
connector_found = 3;
}
if ((tmp = RADEON_BIOS16( bios_header + 0x42 ))) {
if ((tmp0 = RADEON_BIOS16( tmp + 0x15 ))) {
if ((tmp1 = RADEON_BIOS16( tmp0 + 2 ) & 0x07)) {
ptr_entity->port_info[0].ddc_type = tmp1;
if (ptr_entity->port_info[0].ddc_type > ddc_crt2) {
SHOW_INFO( 4, "unknown ddctype %d found",
ptr_entity->port_info[0].ddc_type);
ptr_entity->port_info[0].ddc_type = ddc_none_detected;
}
SHOW_INFO0( 4, "lcd ddc info table found!");
}
}
}
} else if (connector_found == 2) {
memcpy (&ptr_entity->port_info[0],
&ptr_entity->port_info[1],
sizeof (ptr_entity->port_info[0]));
ptr_entity->port_info[1].dac_type = dac_unknown;
ptr_entity->port_info[1].tmds_type = tmds_unknown;
ptr_entity->port_info[1].ddc_type = ddc_none_detected;
ptr_entity->port_info[1].connector_type = connector_none;
connector_found = 1;
}
if (connector_found == 0) {
SHOW_INFO0( 4, "no connector found in connector info table.");
} else {
SHOW_INFO( 2, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d",
0, ptr_entity->port_info[0].ddc_type, ptr_entity->port_info[0].dac_type,
ptr_entity->port_info[0].tmds_type, ptr_entity->port_info[0].connector_type);
}
if (connector_found == 3) {
SHOW_INFO( 2, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d",
1, ptr_entity->port_info[1].ddc_type, ptr_entity->port_info[1].dac_type,
ptr_entity->port_info[1].tmds_type, ptr_entity->port_info[1].connector_type);
}
}
return TRUE;
}
static bool Radeon_GetBIOSDFPInfo( device_info *di )
{
uint16 bios_header;
uint16 fpi_offset;
FPI_BLOCK fpi;
char panel_name[30];
int i;
uint16 tmp;
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 )
{
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;
}
}
else
{
fpi_offset = RADEON_BIOS16(bios_header + 0x40);
if( !fpi_offset ) {
di->fp_info.panel_pwr_delay = 200;
SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
return false;
}
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 );
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);
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;
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;
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;
}
}
SHOW_ERROR0( 2, "Radeon: couldn't get Panel Timing from BIOS" );
return false;
}
static void Radeon_RevEnvDFPSize( device_info *di )
{
vuint8 *regs = di->regs;
di->fp_info.panel_yres =
((INREG( regs, RADEON_FP_VERT_STRETCH ) & RADEON_VERT_PANEL_SIZE)
>> RADEON_VERT_PANEL_SIZE_SHIFT) + 1;
di->fp_info.panel_xres =
(((INREG( regs, RADEON_FP_HORZ_STRETCH ) & RADEON_HORZ_PANEL_SIZE)
>> RADEON_HORZ_PANEL_SIZE_SHIFT) + 1) * 8;
SHOW_INFO( 2, "detected panel size from registers: %dx%d",
di->fp_info.panel_xres, di->fp_info.panel_yres);
}
static void Radeon_RevEnvDFPTiming( device_info *di )
{
vuint8 *regs = di->regs;
uint32 r;
uint16 a, b;
r = INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP );
a = (r & RADEON_FP_CRTC_H_TOTAL_MASK);
b = (r & RADEON_FP_CRTC_H_DISP_MASK) >> RADEON_FP_CRTC_H_DISP_SHIFT;
di->fp_info.h_blank = (a - b) * 8;
SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 );
r = INREG( regs, RADEON_FP_H_SYNC_STRT_WID );
di->fp_info.h_over_plus =
((r & RADEON_FP_H_SYNC_STRT_CHAR_MASK)
>> RADEON_FP_H_SYNC_STRT_CHAR_SHIFT) - b;
di->fp_info.h_over_plus *= 8;
di->fp_info.h_sync_width =
((r & RADEON_FP_H_SYNC_WID_MASK)
>> RADEON_FP_H_SYNC_WID_SHIFT);
di->fp_info.h_sync_width *= 8;
r = INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP );
a = (r & RADEON_FP_CRTC_V_TOTAL_MASK);
b = (r & RADEON_FP_CRTC_V_DISP_MASK) >> RADEON_FP_CRTC_V_DISP_SHIFT;
di->fp_info.v_blank = a - b;
SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b );
r = INREG( regs, RADEON_FP_V_SYNC_STRT_WID );
di->fp_info.v_over_plus = (r & RADEON_FP_V_SYNC_STRT_MASK) - b;
di->fp_info.v_sync_width = ((r & RADEON_FP_V_SYNC_WID_MASK)
>> RADEON_FP_V_SYNC_WID_SHIFT);
r = INREG( regs, RADEON_CRTC_H_TOTAL_DISP );
a = (r & RADEON_CRTC_H_TOTAL);
b = (r & RADEON_CRTC_H_DISP) >> RADEON_CRTC_H_DISP_SHIFT;
di->fp_info.h_blank = (a - b) * 8;
SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 );
r = INREG( regs, RADEON_CRTC_H_SYNC_STRT_WID );
di->fp_info.h_over_plus =
((r & RADEON_CRTC_H_SYNC_STRT_CHAR)
>> RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) - b;
di->fp_info.h_over_plus *= 8;
di->fp_info.h_sync_width =
((r & RADEON_CRTC_H_SYNC_WID)
>> RADEON_CRTC_H_SYNC_WID_SHIFT);
di->fp_info.h_sync_width *= 8;
r = INREG( regs, RADEON_CRTC_V_TOTAL_DISP );
a = (r & RADEON_CRTC_V_TOTAL);
b = (r & RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
di->fp_info.v_blank = a - b;
SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b );
r = INREG( regs, RADEON_CRTC_V_SYNC_STRT_WID );
di->fp_info.v_over_plus = (r & RADEON_CRTC_V_SYNC_STRT) - b;
di->fp_info.v_sync_width = ((r & RADEON_CRTC_V_SYNC_WID)
>> RADEON_CRTC_V_SYNC_WID_SHIFT);
}
static void Radeon_GetTMDSInfoFromBios( device_info *di )
{
uint32 tmp, maxfreq;
uint32 found = FALSE;
int i, n;
uint16 bios_header;
bios_header = RADEON_BIOS16( 0x48 );
for (i = 0; i < 4; i++) {
di->tmds_pll[i].value = 0;
di->tmds_pll[i].freq = 0;
}
if (di->is_atombios)
{
int master_data_start;
master_data_start = RADEON_BIOS16( bios_header + 32 );
if((tmp = RADEON_BIOS16 (master_data_start + 18))) {
maxfreq = RADEON_BIOS16(tmp + 4);
for (i = 0; i < 4; i++) {
di->tmds_pll[i].freq = RADEON_BIOS16(tmp + i * 6 + 6);
di->tmds_pll[i].value = ((RADEON_BIOS8(tmp + i * 6 + 8) & 0x3f) |
((RADEON_BIOS8(tmp + i * 6 + 10) & 0x3f) << 6) |
((RADEON_BIOS8(tmp + i * 6 + 9) & 0xf) << 12) |
((RADEON_BIOS8(tmp + i * 6 + 11) & 0xf) << 16));
SHOW_ERROR( 2, "TMDS PLL from BIOS: %" B_PRIu32 " %" B_PRIx32,
di->tmds_pll[i].freq, di->tmds_pll[i].value);
if (maxfreq == di->tmds_pll[i].freq) {
di->tmds_pll[i].freq = 0xffffffff;
break;
}
}
found = TRUE;
}
} else {
tmp = RADEON_BIOS16(bios_header + 0x34);
if (tmp) {
SHOW_ERROR( 2, "DFP table revision: %d", RADEON_BIOS8(tmp));
if (RADEON_BIOS8(tmp) == 3) {
n = RADEON_BIOS8(tmp + 5) + 1;
if (n > 4)
n = 4;
for (i = 0; i < n; i++) {
di->tmds_pll[i].value = RADEON_BIOS32(tmp + i * 10 + 0x08);
di->tmds_pll[i].freq = RADEON_BIOS16(tmp + i * 10 + 0x10);
}
found = TRUE;
} else if (RADEON_BIOS8(tmp) == 4) {
int stride = 0;
n = RADEON_BIOS8(tmp + 5) + 1;
if (n > 4)
n = 4;
for (i = 0; i < n; i++) {
di->tmds_pll[i].value = RADEON_BIOS32(tmp + stride + 0x08);
di->tmds_pll[i].freq = RADEON_BIOS16(tmp + stride + 0x10);
if (i == 0)
stride += 10;
else
stride += 6;
}
found = TRUE;
}
}
}
if (found == FALSE) {
for (i = 0; i < 4; i++) {
di->tmds_pll[i].value = default_tmds_pll[di->asic][i].value;
di->tmds_pll[i].freq = default_tmds_pll[di->asic][i].freq;
SHOW_ERROR( 2, "TMDS PLL from DEFAULTS: %" B_PRIu32 " %" B_PRIx32,
di->tmds_pll[i].freq, di->tmds_pll[i].value);
}
}
}
static void Radeon_GetFPData( device_info *di )
{
memset( &di->fp_info, 0, sizeof( di->fp_info ));
if( !di->is_mobility )
return;
Radeon_GetBIOSDFPInfo( di );
if( di->fp_info.panel_xres == 0 || di->fp_info.panel_yres == 0)
Radeon_RevEnvDFPSize( di );
if( di->fp_info.h_blank == 0 || di->fp_info.v_blank == 0)
Radeon_RevEnvDFPTiming( di );
SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
di->fp_info.panel_xres, di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width );
SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d",
di->fp_info.panel_yres, di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.v_sync_width );
SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock );
}
static uint32 RADEON_GetAccessibleVRAM( device_info *di )
{
vuint8 *regs = di->regs;
pci_info *pcii = &(di->pcii);
uint32 aper_size = INREG( regs, RADEON_CONFIG_APER_SIZE );
if (di->asic == rt_rv280 ||
di->asic == rt_rv350 ||
di->asic == rt_rv380 ||
di->asic == rt_r420 ) {
OUTREGP( regs, RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL,
~RADEON_HDP_APER_CNTL);
SHOW_INFO0( 0, "Generation 2 PCI interface, using max accessible memory");
return aper_size * 2;
}
if (get_pci(PCI_header_type, 1) & 0x80) {
SHOW_INFO0( 0, "Generation 1 PCI interface in multifunction mode"
", accessible memory limited to one aperture\n");
return aper_size;
}
if (INREG( regs, RADEON_HOST_PATH_CNTL ) & RADEON_HDP_APER_CNTL )
return aper_size * 2;
return aper_size;
}
static void Radeon_DetectRAM( device_info *di )
{
vuint8 *regs = di->regs;
uint32 accessible, bar_size, tmp = 0;
if( di->is_igp ) {
uint32 tom;
tom = INREG( regs, RADEON_NB_TOM );
di->local_mem_size = ((tom >> 16) + 1 - (tom & 0xffff)) << 16;
OUTREG( regs, RADEON_CONFIG_MEMSIZE, di->local_mem_size * 1024);
} else {
di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK;
}
if( di->local_mem_size == 0 ) {
di->local_mem_size = 8 * 1024 *1024;
OUTREG( regs, RADEON_CONFIG_MEMSIZE, di->local_mem_size);
}
accessible = RADEON_GetAccessibleVRAM( di );
bar_size = di->pcii.u.h0.base_register_sizes[0];
if (bar_size == 0)
bar_size = 0x200000;
if (accessible > bar_size)
accessible = bar_size;
SHOW_INFO( 0,
"Detected total video RAM=%" B_PRIu32 "K, "
"accessible=%" B_PRIu32 "K "
"(PCI BAR=%" B_PRIu32 "K)",
di->local_mem_size / 1024,
accessible / 1024,
bar_size / 1024);
if (di->local_mem_size > accessible)
di->local_mem_size = accessible;
tmp = INREG( regs, RADEON_MEM_CNTL );
if (IS_DI_R300_VARIANT) {
tmp &= R300_MEM_NUM_CHANNELS_MASK;
switch (tmp) {
case 0: di->ram.width = 64; break;
case 1: di->ram.width = 128; break;
case 2: di->ram.width = 256; break;
default: di->ram.width = 128; break;
}
} else if ( (di->asic >= rt_rv100) ||
(di->asic >= rt_rs100) ||
(di->asic >= rt_rs200)) {
if (tmp & RV100_HALF_MODE)
di->ram.width = 32;
else
di->ram.width = 64;
} else {
if (tmp & RADEON_MEM_NUM_CHANNELS_MASK)
di->ram.width = 128;
else
di->ram.width = 64;
}
if (di->is_igp || (di->asic >= rt_r300))
{
uint32 mem_type = INREG( regs, RADEON_MEM_SDRAM_MODE_REG ) & RADEON_MEM_CFG_TYPE_MASK;
if ( mem_type == RADEON_MEM_CFG_SDR) {
strcpy(di->ram_type, "SDR SGRAM");
di->ram.ml = 4;
di->ram.MB = 4;
di->ram.Trcd = 1;
di->ram.Trp = 2;
di->ram.Twr = 1;
di->ram.CL = 2;
di->ram.loop_latency = 16;
di->ram.Rloop = 16;
di->ram.Tr2w = 0;
} else {
strcpy(di->ram_type, "DDR SGRAM");
di->ram.ml = 4;
di->ram.MB = 4;
di->ram.Trcd = 3;
di->ram.Trp = 3;
di->ram.Twr = 2;
di->ram.CL = 3;
di->ram.Tr2w = 1;
di->ram.loop_latency = 16;
di->ram.Rloop = 16;
}
}
SHOW_INFO( 1, "%" B_PRIu32 " MB %s found on %d wide bus",
di->local_mem_size / 1024 / 1024, di->ram_type, di->ram.width);
}
status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri )
{
char buffer[100];
sprintf(buffer, "%04X_%04X_%02X%02X%02X bios",
pcii->vendor_id, pcii->device_id,
pcii->bus, pcii->device, pcii->function);
ri->phys_address = 0xc0000;
ri->size = 0x40000;
ri->bios_area = map_physical_memory( buffer, ri->phys_address,
ri->size, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&ri->bios_ptr );
if( ri->bios_area < 0 )
return ri->bios_area;
ri->rom_ptr = Radeon_FindRom( ri );
if( ri->rom_ptr != NULL )
ri->phys_address += ri->rom_ptr - ri->bios_ptr;
return ri->rom_ptr != NULL ? B_OK : B_ERROR;
}
void Radeon_UnmapBIOS( rom_info *ri )
{
delete_area( ri->bios_area );
ri->bios_ptr = ri->rom_ptr = NULL;
}
status_t Radeon_ReadBIOSData( device_info *di )
{
shared_info dummy_si;
status_t result = B_OK;
di->si = &dummy_si;
result = Radeon_MapDevice( di, true );
if( result < 0 )
goto err1;
Radeon_GetPLLInfo( di );
di->routing.port_info[0].mon_type = mt_unknown;
di->routing.port_info[0].ddc_type = ddc_none_detected;
di->routing.port_info[0].dac_type = dac_unknown;
di->routing.port_info[0].tmds_type = tmds_unknown;
di->routing.port_info[0].connector_type = connector_none;
di->routing.port_info[1].mon_type = mt_unknown;
di->routing.port_info[1].ddc_type = ddc_none_detected;
di->routing.port_info[1].dac_type = dac_unknown;
di->routing.port_info[1].tmds_type = tmds_unknown;
di->routing.port_info[1].connector_type = connector_none;
if ( !Radeon_GetConnectorInfoFromBIOS( di ) )
{
di->routing.port_info[0].mon_type = mt_unknown;
di->routing.port_info[0].ddc_type = ddc_none_detected;
di->routing.port_info[0].dac_type = dac_tvdac;
di->routing.port_info[0].tmds_type = tmds_unknown;
di->routing.port_info[0].connector_type = connector_proprietary;
di->routing.port_info[1].mon_type = mt_unknown;
di->routing.port_info[1].ddc_type = ddc_none_detected;
di->routing.port_info[1].dac_type = dac_primary;
di->routing.port_info[1].tmds_type = tmds_ext;
di->routing.port_info[1].connector_type = connector_crt;
}
Radeon_GetFPData( di );
Radeon_GetTMDSInfoFromBios( di );
Radeon_DetectRAM( di );
Radeon_UnmapDevice( di );
err1:
di->si = NULL;
return result;
}