1*1da2dde8Sshadow303 /* 2*1da2dde8Sshadow303 Copyright (c) 2002, Thomas Kurschel 3*1da2dde8Sshadow303 4*1da2dde8Sshadow303 5*1da2dde8Sshadow303 Part of Radeon kernel driver 6*1da2dde8Sshadow303 7*1da2dde8Sshadow303 BIOS detection and retrieval of vital data 8*1da2dde8Sshadow303 9*1da2dde8Sshadow303 Most of this data should be gathered directly, 10*1da2dde8Sshadow303 especially monitor detection should be done on 11*1da2dde8Sshadow303 demand so not all monitors need to be connected 12*1da2dde8Sshadow303 during boot 13*1da2dde8Sshadow303 */ 14*1da2dde8Sshadow303 15*1da2dde8Sshadow303 #include "radeon_driver.h" 16*1da2dde8Sshadow303 #include <mmio.h> 17*1da2dde8Sshadow303 #include <bios_regs.h> 18*1da2dde8Sshadow303 #include <config_regs.h> 19*1da2dde8Sshadow303 #include <memcntrl_regs.h> 20*1da2dde8Sshadow303 #include <fp_regs.h> 21*1da2dde8Sshadow303 #include <crtc_regs.h> 22*1da2dde8Sshadow303 #include <radeon_bios.h> 23*1da2dde8Sshadow303 //#include "../common/utils.h" 24*1da2dde8Sshadow303 25*1da2dde8Sshadow303 #include <stdio.h> 26*1da2dde8Sshadow303 #include <string.h> 27*1da2dde8Sshadow303 28*1da2dde8Sshadow303 static const char ati_rom_sig[] = "761295520"; 29*1da2dde8Sshadow303 static const char *radeon_sig[] = { 30*1da2dde8Sshadow303 "RG6", // r200 31*1da2dde8Sshadow303 "RADEON", // r100 32*1da2dde8Sshadow303 "M6", // mobile version of r100 33*1da2dde8Sshadow303 // probably an M6P; 34*1da2dde8Sshadow303 // anyway - this is the card I wrote this driver for! 35*1da2dde8Sshadow303 // (perhaps ATI tries to make the card incompatible to standard drivers) 36*1da2dde8Sshadow303 "P6", 37*1da2dde8Sshadow303 "RV200", // rv200 38*1da2dde8Sshadow303 "RV100", // rv100 39*1da2dde8Sshadow303 "M7", // m7 40*1da2dde8Sshadow303 "RV250", // rv250 R9100 41*1da2dde8Sshadow303 "V280", // RV280 R9200 42*1da2dde8Sshadow303 "R300", // R300 R9500 / R9700 43*1da2dde8Sshadow303 "R350", // R350 R9800 44*1da2dde8Sshadow303 "R360", // R360 R9800 XT 45*1da2dde8Sshadow303 "V350", // RV350 R9600 46*1da2dde8Sshadow303 "V360", // RV350 R9600 XT :guess 47*1da2dde8Sshadow303 "M9" // guess: m9 48*1da2dde8Sshadow303 }; 49*1da2dde8Sshadow303 50*1da2dde8Sshadow303 void Radeon_DetectRAM( device_info *di ); 51*1da2dde8Sshadow303 52*1da2dde8Sshadow303 53*1da2dde8Sshadow303 // find address of ROM 54*1da2dde8Sshadow303 static char *Radeon_FindRom( rom_info *ri ) 55*1da2dde8Sshadow303 { 56*1da2dde8Sshadow303 uint32 segstart; 57*1da2dde8Sshadow303 char *rom_base; 58*1da2dde8Sshadow303 char *rom; 59*1da2dde8Sshadow303 int stage; 60*1da2dde8Sshadow303 int i,j; 61*1da2dde8Sshadow303 62*1da2dde8Sshadow303 for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) { 63*1da2dde8Sshadow303 stage = 1; 64*1da2dde8Sshadow303 65*1da2dde8Sshadow303 // find ROM 66*1da2dde8Sshadow303 rom_base = ri->bios_ptr + segstart - 0xc0000; 67*1da2dde8Sshadow303 68*1da2dde8Sshadow303 if( *rom_base == 0x55 && ((*(rom_base + 1)) & 0xff) == 0xaa ) 69*1da2dde8Sshadow303 stage = 2; 70*1da2dde8Sshadow303 71*1da2dde8Sshadow303 if (stage != 2) 72*1da2dde8Sshadow303 continue; 73*1da2dde8Sshadow303 74*1da2dde8Sshadow303 // find signature of ATI 75*1da2dde8Sshadow303 rom = rom_base; 76*1da2dde8Sshadow303 77*1da2dde8Sshadow303 for( i = 0; i < 128 - (int)strlen( ati_rom_sig ) && stage != 3; i++ ) { 78*1da2dde8Sshadow303 if( ati_rom_sig[0] == *rom ) { 79*1da2dde8Sshadow303 if( strncmp(ati_rom_sig, rom, strlen( ati_rom_sig )) == 0 ) 80*1da2dde8Sshadow303 stage = 3; 81*1da2dde8Sshadow303 } 82*1da2dde8Sshadow303 rom++; 83*1da2dde8Sshadow303 } 84*1da2dde8Sshadow303 85*1da2dde8Sshadow303 if( stage != 3 ) 86*1da2dde8Sshadow303 continue; 87*1da2dde8Sshadow303 88*1da2dde8Sshadow303 // find signature of card 89*1da2dde8Sshadow303 rom = rom_base; 90*1da2dde8Sshadow303 91*1da2dde8Sshadow303 for( i = 0; (i < 512) && (stage != 4); i++ ) { 92*1da2dde8Sshadow303 for( j = 0; j < (int)sizeof( radeon_sig ) / (int)sizeof( radeon_sig[0] ); j++ ) { 93*1da2dde8Sshadow303 if( radeon_sig[j][0] == *rom ) { 94*1da2dde8Sshadow303 if( strncmp( radeon_sig[j], rom, strlen( radeon_sig[j] )) == 0 ) { 95*1da2dde8Sshadow303 SHOW_INFO( 2, "Signature: %s", radeon_sig[j] ); 96*1da2dde8Sshadow303 stage = 4; 97*1da2dde8Sshadow303 break; 98*1da2dde8Sshadow303 } 99*1da2dde8Sshadow303 } 100*1da2dde8Sshadow303 } 101*1da2dde8Sshadow303 rom++; 102*1da2dde8Sshadow303 } 103*1da2dde8Sshadow303 104*1da2dde8Sshadow303 if( stage != 4 ) 105*1da2dde8Sshadow303 continue; 106*1da2dde8Sshadow303 107*1da2dde8Sshadow303 SHOW_INFO( 2, "found ROM @0x%lx", segstart ); 108*1da2dde8Sshadow303 return rom_base; 109*1da2dde8Sshadow303 } 110*1da2dde8Sshadow303 111*1da2dde8Sshadow303 SHOW_INFO0( 2, "no ROM found" ); 112*1da2dde8Sshadow303 return NULL; 113*1da2dde8Sshadow303 } 114*1da2dde8Sshadow303 115*1da2dde8Sshadow303 116*1da2dde8Sshadow303 // PLL info is stored in ROM, probably to easily replace it 117*1da2dde8Sshadow303 // and thus produce cards with different timings 118*1da2dde8Sshadow303 static void Radeon_GetPLLInfo( device_info *di ) 119*1da2dde8Sshadow303 { 120*1da2dde8Sshadow303 uint8 *bios_header; 121*1da2dde8Sshadow303 PLL_BLOCK pll, *pll_info; 122*1da2dde8Sshadow303 123*1da2dde8Sshadow303 bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48); 124*1da2dde8Sshadow303 pll_info = (PLL_BLOCK *)(di->rom.rom_ptr + *(uint16 *)(bios_header + 0x30)); 125*1da2dde8Sshadow303 126*1da2dde8Sshadow303 memcpy( &pll, pll_info, sizeof( pll )); 127*1da2dde8Sshadow303 128*1da2dde8Sshadow303 di->pll.xclk = (uint32)pll.XCLK; 129*1da2dde8Sshadow303 di->pll.ref_freq = (uint32)pll.PCLK_ref_freq; 130*1da2dde8Sshadow303 di->pll.ref_div = (uint32)pll.PCLK_ref_divider; 131*1da2dde8Sshadow303 di->pll.min_pll_freq = pll.PCLK_min_freq; 132*1da2dde8Sshadow303 di->pll.max_pll_freq = pll.PCLK_max_freq; 133*1da2dde8Sshadow303 134*1da2dde8Sshadow303 SHOW_INFO( 2, "ref_clk=%ld, ref_div=%ld, xclk=%ld, min_freq=%ld, max_freq=%ld from BIOS", 135*1da2dde8Sshadow303 di->pll.ref_freq, di->pll.ref_div, di->pll.xclk, 136*1da2dde8Sshadow303 di->pll.min_pll_freq, di->pll.max_pll_freq ); 137*1da2dde8Sshadow303 } 138*1da2dde8Sshadow303 139*1da2dde8Sshadow303 const char *Mon2Str[] = { 140*1da2dde8Sshadow303 "N/C", 141*1da2dde8Sshadow303 "CRT", 142*1da2dde8Sshadow303 "CRT", 143*1da2dde8Sshadow303 "Laptop flatpanel", 144*1da2dde8Sshadow303 "DVI (flatpanel)", 145*1da2dde8Sshadow303 "secondary DVI (flatpanel) - unsupported", 146*1da2dde8Sshadow303 "Composite TV - unsupported", 147*1da2dde8Sshadow303 "S-Video out - unsupported" 148*1da2dde8Sshadow303 }; 149*1da2dde8Sshadow303 150*1da2dde8Sshadow303 // ask BIOS what kind of monitor is connected to each port 151*1da2dde8Sshadow303 static void Radeon_GetMonType( device_info *di ) 152*1da2dde8Sshadow303 { 153*1da2dde8Sshadow303 unsigned int tmp; 154*1da2dde8Sshadow303 155*1da2dde8Sshadow303 SHOW_FLOW0( 3, "" ); 156*1da2dde8Sshadow303 157*1da2dde8Sshadow303 di->disp_type[0] = di->disp_type[1] = dt_none; 158*1da2dde8Sshadow303 159*1da2dde8Sshadow303 if (di->has_crtc2) { 160*1da2dde8Sshadow303 tmp = INREG( di->regs, RADEON_BIOS_4_SCRATCH ); 161*1da2dde8Sshadow303 162*1da2dde8Sshadow303 // ordering of "if"s is important are multiple 163*1da2dde8Sshadow303 // devices can be concurrently connected to one port 164*1da2dde8Sshadow303 // (like both a CRT and a TV) 165*1da2dde8Sshadow303 166*1da2dde8Sshadow303 // primary port 167*1da2dde8Sshadow303 if (tmp & 0x08) 168*1da2dde8Sshadow303 di->disp_type[0] = dt_dvi_1; 169*1da2dde8Sshadow303 else if (tmp & 0x4) 170*1da2dde8Sshadow303 di->disp_type[0] = dt_lvds; 171*1da2dde8Sshadow303 else if (tmp & 0x200) 172*1da2dde8Sshadow303 di->disp_type[0] = dt_crt_1; 173*1da2dde8Sshadow303 else if (tmp & 0x10) 174*1da2dde8Sshadow303 di->disp_type[0] = dt_ctv; 175*1da2dde8Sshadow303 else if (tmp & 0x20) 176*1da2dde8Sshadow303 di->disp_type[0] = dt_stv; 177*1da2dde8Sshadow303 178*1da2dde8Sshadow303 // secondary port 179*1da2dde8Sshadow303 if (tmp & 0x2) 180*1da2dde8Sshadow303 di->disp_type[1] = dt_crt_2; 181*1da2dde8Sshadow303 else if (tmp & 0x800) 182*1da2dde8Sshadow303 di->disp_type[1] = dt_dvi_2; 183*1da2dde8Sshadow303 else if (tmp & 0x400) 184*1da2dde8Sshadow303 // this is unlikely - I only know about one LVDS unit 185*1da2dde8Sshadow303 di->disp_type[1] = dt_lvds; 186*1da2dde8Sshadow303 else if (tmp & 0x1000) 187*1da2dde8Sshadow303 di->disp_type[1] = dt_ctv; 188*1da2dde8Sshadow303 else if (tmp & 0x2000) 189*1da2dde8Sshadow303 di->disp_type[1] = dt_stv; 190*1da2dde8Sshadow303 } else { 191*1da2dde8Sshadow303 // regular Radeon 192*1da2dde8Sshadow303 di->disp_type[0] = dt_none; 193*1da2dde8Sshadow303 194*1da2dde8Sshadow303 tmp = INREG( di->regs, RADEON_FP_GEN_CNTL); 195*1da2dde8Sshadow303 196*1da2dde8Sshadow303 if( tmp & RADEON_FP_EN_TMDS ) 197*1da2dde8Sshadow303 di->disp_type[0] = dt_dvi_1; 198*1da2dde8Sshadow303 else 199*1da2dde8Sshadow303 di->disp_type[0] = dt_crt_1; 200*1da2dde8Sshadow303 } 201*1da2dde8Sshadow303 202*1da2dde8Sshadow303 SHOW_INFO( 1, "BIOS reports %s on primary and %s on secondary port", 203*1da2dde8Sshadow303 Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]); 204*1da2dde8Sshadow303 205*1da2dde8Sshadow303 // remove unsupported devices 206*1da2dde8Sshadow303 if( di->disp_type[0] >= dt_dvi_2 ) 207*1da2dde8Sshadow303 di->disp_type[0] = dt_none; 208*1da2dde8Sshadow303 if( di->disp_type[1] >= dt_dvi_2 ) 209*1da2dde8Sshadow303 di->disp_type[1] = dt_none; 210*1da2dde8Sshadow303 211*1da2dde8Sshadow303 // HACK: overlays can only be shown on first CRTC; 212*1da2dde8Sshadow303 // if there's nothing on first port, connect 213*1da2dde8Sshadow303 // second port to first CRTC (proper signal routing 214*1da2dde8Sshadow303 // is hopefully done by BIOS) 215*1da2dde8Sshadow303 if( di->has_crtc2 ) { 216*1da2dde8Sshadow303 if( di->disp_type[0] == dt_none && di->disp_type[1] == dt_crt_2 ) { 217*1da2dde8Sshadow303 di->disp_type[0] = dt_crt_1; 218*1da2dde8Sshadow303 di->disp_type[1] = dt_none; 219*1da2dde8Sshadow303 } 220*1da2dde8Sshadow303 } 221*1da2dde8Sshadow303 222*1da2dde8Sshadow303 SHOW_INFO( 1, "Effective routing: %s on primary and %s on secondary port", 223*1da2dde8Sshadow303 Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]); 224*1da2dde8Sshadow303 } 225*1da2dde8Sshadow303 226*1da2dde8Sshadow303 227*1da2dde8Sshadow303 // get flat panel info (does only make sense for Laptops 228*1da2dde8Sshadow303 // with integrated display, but looking for it doesn't hurt, 229*1da2dde8Sshadow303 // who knows which strange kind of combination is out there?) 230*1da2dde8Sshadow303 static bool Radeon_GetBIOSDFPInfo( device_info *di ) 231*1da2dde8Sshadow303 { 232*1da2dde8Sshadow303 uint8 *bios_header; 233*1da2dde8Sshadow303 uint16 fpi_offset; 234*1da2dde8Sshadow303 FPI_BLOCK fpi; 235*1da2dde8Sshadow303 char panel_name[30]; 236*1da2dde8Sshadow303 int i; 237*1da2dde8Sshadow303 238*1da2dde8Sshadow303 bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48); 239*1da2dde8Sshadow303 240*1da2dde8Sshadow303 fpi_offset = *(uint16 *)(bios_header + 0x40); 241*1da2dde8Sshadow303 242*1da2dde8Sshadow303 if( !fpi_offset ) { 243*1da2dde8Sshadow303 di->fp_info.panel_pwr_delay = 200; 244*1da2dde8Sshadow303 SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" ); 245*1da2dde8Sshadow303 return false; 246*1da2dde8Sshadow303 } 247*1da2dde8Sshadow303 248*1da2dde8Sshadow303 memcpy( &fpi, di->rom.rom_ptr + fpi_offset, sizeof( fpi )); 249*1da2dde8Sshadow303 250*1da2dde8Sshadow303 memcpy( panel_name, &fpi.name, sizeof( fpi.name ) ); 251*1da2dde8Sshadow303 panel_name[sizeof( fpi.name )] = 0; 252*1da2dde8Sshadow303 253*1da2dde8Sshadow303 SHOW_INFO( 2, "Panel ID string: %s", panel_name ); 254*1da2dde8Sshadow303 255*1da2dde8Sshadow303 di->fp_info.panel_xres = fpi.panel_xres; 256*1da2dde8Sshadow303 di->fp_info.panel_yres = fpi.panel_yres; 257*1da2dde8Sshadow303 258*1da2dde8Sshadow303 SHOW_INFO( 2, "Panel Size from BIOS: %dx%d", 259*1da2dde8Sshadow303 di->fp_info.panel_xres, di->fp_info.panel_yres); 260*1da2dde8Sshadow303 261*1da2dde8Sshadow303 di->fp_info.panel_pwr_delay = fpi.panel_pwr_delay; 262*1da2dde8Sshadow303 if( di->fp_info.panel_pwr_delay > 2000 || di->fp_info.panel_pwr_delay < 0 ) 263*1da2dde8Sshadow303 di->fp_info.panel_pwr_delay = 2000; 264*1da2dde8Sshadow303 265*1da2dde8Sshadow303 // there might be multiple supported resolutions stored; 266*1da2dde8Sshadow303 // we are looking for native resolution 267*1da2dde8Sshadow303 for( i = 0; i < 20; ++i ) { 268*1da2dde8Sshadow303 uint16 fpi_timing_ofs; 269*1da2dde8Sshadow303 FPI_TIMING_BLOCK fpi_timing; 270*1da2dde8Sshadow303 271*1da2dde8Sshadow303 fpi_timing_ofs = fpi.fpi_timing_ofs[i]; 272*1da2dde8Sshadow303 273*1da2dde8Sshadow303 if( fpi_timing_ofs == 0 ) 274*1da2dde8Sshadow303 break; 275*1da2dde8Sshadow303 276*1da2dde8Sshadow303 memcpy( &fpi_timing, di->rom.rom_ptr + fpi_timing_ofs, sizeof( fpi_timing )); 277*1da2dde8Sshadow303 278*1da2dde8Sshadow303 if( fpi_timing.panel_xres != di->fp_info.panel_xres || 279*1da2dde8Sshadow303 fpi_timing.panel_yres != di->fp_info.panel_yres ) 280*1da2dde8Sshadow303 continue; 281*1da2dde8Sshadow303 282*1da2dde8Sshadow303 di->fp_info.h_blank = (fpi_timing.h_total - fpi_timing.h_display) * 8; 283*1da2dde8Sshadow303 // TBD: seems like upper four bits of hsync_start contain garbage 284*1da2dde8Sshadow303 di->fp_info.h_over_plus = ((fpi_timing.h_sync_start & 0xfff) - fpi_timing.h_display - 1) * 8; 285*1da2dde8Sshadow303 di->fp_info.h_sync_width = fpi_timing.h_sync_width * 8; 286*1da2dde8Sshadow303 di->fp_info.v_blank = fpi_timing.v_total - fpi_timing.v_display; 287*1da2dde8Sshadow303 di->fp_info.v_over_plus = (fpi_timing.v_sync & 0x7ff) - fpi_timing.v_display; 288*1da2dde8Sshadow303 di->fp_info.v_sync_width = (fpi_timing.v_sync & 0xf800) >> 11; 289*1da2dde8Sshadow303 di->fp_info.dot_clock = fpi_timing.dot_clock * 10; 290*1da2dde8Sshadow303 return true; 291*1da2dde8Sshadow303 } 292*1da2dde8Sshadow303 293*1da2dde8Sshadow303 SHOW_ERROR0( 2, "Radeon: couldn't get Panel Timing from BIOS" ); 294*1da2dde8Sshadow303 return false; 295*1da2dde8Sshadow303 } 296*1da2dde8Sshadow303 297*1da2dde8Sshadow303 298*1da2dde8Sshadow303 // try to reverse engineer DFP specification from 299*1da2dde8Sshadow303 // timing currently set up in graphics cards registers 300*1da2dde8Sshadow303 // (effectively, we hope that BIOS has set it up correctly 301*1da2dde8Sshadow303 // and noone has messed registers up yet; let's pray) 302*1da2dde8Sshadow303 static void Radeon_RevEnvDFPSize( device_info *di ) 303*1da2dde8Sshadow303 { 304*1da2dde8Sshadow303 vuint8 *regs = di->regs; 305*1da2dde8Sshadow303 /* uint32 r; 306*1da2dde8Sshadow303 307*1da2dde8Sshadow303 // take a look at flat_panel.c of the accelerant how register values 308*1da2dde8Sshadow303 // are calculated - this is the inverse function 309*1da2dde8Sshadow303 r = INREG( regs, RADEON_FP_VERT_STRETCH ); 310*1da2dde8Sshadow303 if( (r & RADEON_VERT_STRETCH_BLEND) == 0 ) { 311*1da2dde8Sshadow303 di->fp_info.panel_yres = 312*1da2dde8Sshadow303 ((r & RADEON_VERT_PANEL_SIZE) >> RADEON_VERT_PANEL_SHIFT) + 1; 313*1da2dde8Sshadow303 } else { 314*1da2dde8Sshadow303 uint32 v_total = (INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP ) 315*1da2dde8Sshadow303 >> RADEON_FP_CRTC_V_DISP_SHIFT) + 1; 316*1da2dde8Sshadow303 SHOW_INFO( 2, "stretched mode: v_total=%d", v_total ); 317*1da2dde8Sshadow303 di->fp_info.panel_yres = 318*1da2dde8Sshadow303 (v_total * FIX_SCALE * RADEON_VERT_STRETCH_RATIO_MAX / 319*1da2dde8Sshadow303 (r & RADEON_VERT_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT; 320*1da2dde8Sshadow303 // seems to be a BIOS bug - vertical size is 1 point too small 321*1da2dde8Sshadow303 // (checked by re-calculating stretch factor) 322*1da2dde8Sshadow303 ++di->fp_info.panel_yres; 323*1da2dde8Sshadow303 } 324*1da2dde8Sshadow303 325*1da2dde8Sshadow303 r = INREG( regs, RADEON_FP_HORZ_STRETCH ); 326*1da2dde8Sshadow303 if( (r & RADEON_HORZ_STRETCH_BLEND) == 0 ) { 327*1da2dde8Sshadow303 di->fp_info.panel_xres = 328*1da2dde8Sshadow303 (((r & RADEON_HORZ_PANEL_SIZE) >> RADEON_HORZ_PANEL_SHIFT) + 1) * 8; 329*1da2dde8Sshadow303 } else { 330*1da2dde8Sshadow303 uint32 h_total = ((INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP ) 331*1da2dde8Sshadow303 >> RADEON_FP_CRTC_H_DISP_SHIFT) + 1) * 8; 332*1da2dde8Sshadow303 SHOW_INFO( 2, "stretched mode: h_total=%d", h_total ); 333*1da2dde8Sshadow303 di->fp_info.panel_xres = 334*1da2dde8Sshadow303 (h_total * FIX_SCALE * RADEON_HORZ_STRETCH_RATIO_MAX / 335*1da2dde8Sshadow303 (r & RADEON_HORZ_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT; 336*1da2dde8Sshadow303 }*/ 337*1da2dde8Sshadow303 338*1da2dde8Sshadow303 di->fp_info.panel_yres = 339*1da2dde8Sshadow303 ((INREG( regs, RADEON_FP_VERT_STRETCH ) & RADEON_VERT_PANEL_SIZE) 340*1da2dde8Sshadow303 >> RADEON_VERT_PANEL_SHIFT) + 1; 341*1da2dde8Sshadow303 342*1da2dde8Sshadow303 di->fp_info.panel_xres = 343*1da2dde8Sshadow303 (((INREG( regs, RADEON_FP_HORZ_STRETCH ) & RADEON_HORZ_PANEL_SIZE) 344*1da2dde8Sshadow303 >> RADEON_HORZ_PANEL_SHIFT) + 1) * 8; 345*1da2dde8Sshadow303 346*1da2dde8Sshadow303 SHOW_INFO( 2, "detected panel size from registers: %dx%d", 347*1da2dde8Sshadow303 di->fp_info.panel_xres, di->fp_info.panel_yres); 348*1da2dde8Sshadow303 } 349*1da2dde8Sshadow303 350*1da2dde8Sshadow303 351*1da2dde8Sshadow303 // once more for getting precise timing 352*1da2dde8Sshadow303 static void Radeon_RevEnvDFPTiming( device_info *di ) 353*1da2dde8Sshadow303 { 354*1da2dde8Sshadow303 vuint8 *regs = di->regs; 355*1da2dde8Sshadow303 uint32 r; 356*1da2dde8Sshadow303 uint16 a, b; 357*1da2dde8Sshadow303 358*1da2dde8Sshadow303 359*1da2dde8Sshadow303 r = INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP ); 360*1da2dde8Sshadow303 // the magic "4" was found by trial and error and probably stems from fudge (see crtc.c) 361*1da2dde8Sshadow303 a = (r & RADEON_FP_CRTC_H_TOTAL_MASK)/* + 4*/; 362*1da2dde8Sshadow303 b = (r & RADEON_FP_CRTC_H_DISP_MASK) >> RADEON_FP_CRTC_H_DISP_SHIFT; 363*1da2dde8Sshadow303 di->fp_info.h_blank = (a - b) * 8; 364*1da2dde8Sshadow303 365*1da2dde8Sshadow303 SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 ); 366*1da2dde8Sshadow303 367*1da2dde8Sshadow303 r = INREG( regs, RADEON_FP_H_SYNC_STRT_WID ); 368*1da2dde8Sshadow303 di->fp_info.h_over_plus = 369*1da2dde8Sshadow303 ((r & RADEON_FP_H_SYNC_STRT_CHAR_MASK) 370*1da2dde8Sshadow303 >> RADEON_FP_H_SYNC_STRT_CHAR_SHIFT) - b/* - 1*/; 371*1da2dde8Sshadow303 di->fp_info.h_over_plus *= 8; 372*1da2dde8Sshadow303 di->fp_info.h_sync_width = 373*1da2dde8Sshadow303 ((r & RADEON_FP_H_SYNC_WID_MASK) 374*1da2dde8Sshadow303 >> RADEON_FP_H_SYNC_WID_SHIFT); 375*1da2dde8Sshadow303 // TBD: this seems to be wrong 376*1da2dde8Sshadow303 // (BIOS tells 112, this calculation leads to 24!) 377*1da2dde8Sshadow303 di->fp_info.h_sync_width *= 8; 378*1da2dde8Sshadow303 379*1da2dde8Sshadow303 r = INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP ); 380*1da2dde8Sshadow303 a = (r & RADEON_FP_CRTC_V_TOTAL_MASK)/* + 1*/; 381*1da2dde8Sshadow303 b = (r & RADEON_FP_CRTC_V_DISP_MASK) >> RADEON_FP_CRTC_V_DISP_SHIFT; 382*1da2dde8Sshadow303 di->fp_info.v_blank = a - b; 383*1da2dde8Sshadow303 384*1da2dde8Sshadow303 SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b ); 385*1da2dde8Sshadow303 386*1da2dde8Sshadow303 r = INREG( regs, RADEON_FP_V_SYNC_STRT_WID ); 387*1da2dde8Sshadow303 di->fp_info.v_over_plus = (r & RADEON_FP_V_SYNC_STRT_MASK) - b; 388*1da2dde8Sshadow303 di->fp_info.v_sync_width = ((r & RADEON_FP_V_SYNC_WID_MASK) 389*1da2dde8Sshadow303 >> RADEON_FP_V_SYNC_WID_SHIFT)/* + 1*/; 390*1da2dde8Sshadow303 391*1da2dde8Sshadow303 // standard CRTC 392*1da2dde8Sshadow303 393*1da2dde8Sshadow303 r = INREG( regs, RADEON_CRTC_H_TOTAL_DISP ); 394*1da2dde8Sshadow303 a = (r & RADEON_CRTC_H_TOTAL); 395*1da2dde8Sshadow303 b = (r & RADEON_CRTC_H_DISP) >> RADEON_CRTC_H_DISP_SHIFT; 396*1da2dde8Sshadow303 di->fp_info.h_blank = (a - b) * 8; 397*1da2dde8Sshadow303 398*1da2dde8Sshadow303 SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 ); 399*1da2dde8Sshadow303 400*1da2dde8Sshadow303 r = INREG( regs, RADEON_CRTC_H_SYNC_STRT_WID ); 401*1da2dde8Sshadow303 di->fp_info.h_over_plus = 402*1da2dde8Sshadow303 ((r & RADEON_CRTC_H_SYNC_STRT_CHAR) 403*1da2dde8Sshadow303 >> RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) - b; 404*1da2dde8Sshadow303 di->fp_info.h_over_plus *= 8; 405*1da2dde8Sshadow303 di->fp_info.h_sync_width = 406*1da2dde8Sshadow303 ((r & RADEON_CRTC_H_SYNC_WID) 407*1da2dde8Sshadow303 >> RADEON_CRTC_H_SYNC_WID_SHIFT); 408*1da2dde8Sshadow303 di->fp_info.h_sync_width *= 8; 409*1da2dde8Sshadow303 410*1da2dde8Sshadow303 r = INREG( regs, RADEON_CRTC_V_TOTAL_DISP ); 411*1da2dde8Sshadow303 a = (r & RADEON_CRTC_V_TOTAL); 412*1da2dde8Sshadow303 b = (r & RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT; 413*1da2dde8Sshadow303 di->fp_info.v_blank = a - b; 414*1da2dde8Sshadow303 415*1da2dde8Sshadow303 SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b ); 416*1da2dde8Sshadow303 417*1da2dde8Sshadow303 r = INREG( regs, RADEON_CRTC_V_SYNC_STRT_WID ); 418*1da2dde8Sshadow303 di->fp_info.v_over_plus = (r & RADEON_CRTC_V_SYNC_STRT) - b; 419*1da2dde8Sshadow303 di->fp_info.v_sync_width = ((r & RADEON_CRTC_V_SYNC_WID) 420*1da2dde8Sshadow303 >> RADEON_CRTC_V_SYNC_WID_SHIFT); 421*1da2dde8Sshadow303 } 422*1da2dde8Sshadow303 423*1da2dde8Sshadow303 424*1da2dde8Sshadow303 // get everything in terms of monitors connected to the card 425*1da2dde8Sshadow303 static void Radeon_GetBIOSMon( device_info *di ) 426*1da2dde8Sshadow303 { 427*1da2dde8Sshadow303 Radeon_GetMonType( di ); 428*1da2dde8Sshadow303 429*1da2dde8Sshadow303 // reset all Flat Panel Info; 430*1da2dde8Sshadow303 // it gets filled out step by step, and this way we know what's still missing 431*1da2dde8Sshadow303 memset( &di->fp_info, 0, sizeof( di->fp_info )); 432*1da2dde8Sshadow303 433*1da2dde8Sshadow303 // we assume that the only fp port is combined with standard port 0 434*1da2dde8Sshadow303 di->fp_info.disp_type = di->disp_type[0]; 435*1da2dde8Sshadow303 436*1da2dde8Sshadow303 if( di->disp_type[0] == dt_dvi_1 || di->disp_type[0] == dt_lvds ) 437*1da2dde8Sshadow303 { 438*1da2dde8Sshadow303 // there is a flat panel - get info about it 439*1da2dde8Sshadow303 Radeon_GetBIOSDFPInfo( di ); 440*1da2dde8Sshadow303 441*1da2dde8Sshadow303 // if BIOS doesn't know, ask the registers 442*1da2dde8Sshadow303 if( di->fp_info.panel_xres == 0 || di->fp_info.panel_yres == 0) 443*1da2dde8Sshadow303 Radeon_RevEnvDFPSize( di ); 444*1da2dde8Sshadow303 445*1da2dde8Sshadow303 if( di->fp_info.h_blank == 0 || di->fp_info.v_blank == 0) 446*1da2dde8Sshadow303 Radeon_RevEnvDFPTiming( di ); 447*1da2dde8Sshadow303 448*1da2dde8Sshadow303 SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d", 449*1da2dde8Sshadow303 di->fp_info.panel_xres, di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width ); 450*1da2dde8Sshadow303 SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d", 451*1da2dde8Sshadow303 di->fp_info.panel_yres, di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.v_sync_width ); 452*1da2dde8Sshadow303 SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock ); 453*1da2dde8Sshadow303 } 454*1da2dde8Sshadow303 } 455*1da2dde8Sshadow303 456*1da2dde8Sshadow303 457*1da2dde8Sshadow303 // detect amount of graphics memory 458*1da2dde8Sshadow303 void Radeon_DetectRAM( device_info *di ) 459*1da2dde8Sshadow303 { 460*1da2dde8Sshadow303 vuint8 *regs = di->regs; 461*1da2dde8Sshadow303 462*1da2dde8Sshadow303 di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK; 463*1da2dde8Sshadow303 464*1da2dde8Sshadow303 // some production boards of m6 will return 0 if it's 8 MB 465*1da2dde8Sshadow303 if( di->local_mem_size == 0 ) 466*1da2dde8Sshadow303 di->local_mem_size = 8 * 1024 *1024; 467*1da2dde8Sshadow303 468*1da2dde8Sshadow303 switch( INREG( regs, RADEON_MEM_SDRAM_MODE_REG ) & RADEON_MEM_CFG_TYPE_MASK ) { 469*1da2dde8Sshadow303 case RADEON_MEM_CFG_SDR: 470*1da2dde8Sshadow303 // SDR SGRAM (2:1) 471*1da2dde8Sshadow303 strcpy(di->ram_type, "SDR SGRAM"); 472*1da2dde8Sshadow303 di->ram.ml = 4; 473*1da2dde8Sshadow303 di->ram.MB = 4; 474*1da2dde8Sshadow303 di->ram.Trcd = 1; 475*1da2dde8Sshadow303 di->ram.Trp = 2; 476*1da2dde8Sshadow303 di->ram.Twr = 1; 477*1da2dde8Sshadow303 di->ram.CL = 2; 478*1da2dde8Sshadow303 di->ram.loop_latency = 16; 479*1da2dde8Sshadow303 di->ram.Rloop = 16; 480*1da2dde8Sshadow303 di->ram.Tr2w = 0; 481*1da2dde8Sshadow303 break; 482*1da2dde8Sshadow303 483*1da2dde8Sshadow303 case RADEON_MEM_CFG_DDR: 484*1da2dde8Sshadow303 // DDR SGRAM 485*1da2dde8Sshadow303 strcpy(di->ram_type, "DDR SGRAM"); 486*1da2dde8Sshadow303 di->ram.ml = 4; 487*1da2dde8Sshadow303 di->ram.MB = 4; 488*1da2dde8Sshadow303 di->ram.Trcd = 3; 489*1da2dde8Sshadow303 di->ram.Trp = 3; 490*1da2dde8Sshadow303 di->ram.Twr = 2; 491*1da2dde8Sshadow303 di->ram.CL = 3; 492*1da2dde8Sshadow303 di->ram.Tr2w = 1; 493*1da2dde8Sshadow303 di->ram.loop_latency = 16; 494*1da2dde8Sshadow303 di->ram.Rloop = 16; 495*1da2dde8Sshadow303 break; 496*1da2dde8Sshadow303 497*1da2dde8Sshadow303 // only one bit, so there's no default 498*1da2dde8Sshadow303 } 499*1da2dde8Sshadow303 500*1da2dde8Sshadow303 SHOW_INFO( 1, "%ld MB %s found", di->local_mem_size / 1024 / 1024, 501*1da2dde8Sshadow303 di->ram_type ); 502*1da2dde8Sshadow303 503*1da2dde8Sshadow303 if( di->local_mem_size > 64 * 1024 * 1024 ) { 504*1da2dde8Sshadow303 di->local_mem_size = 64 * 1024 * 1024; 505*1da2dde8Sshadow303 506*1da2dde8Sshadow303 SHOW_INFO0( 1, "restricted to 64 MB" ); 507*1da2dde8Sshadow303 } 508*1da2dde8Sshadow303 } 509*1da2dde8Sshadow303 510*1da2dde8Sshadow303 511*1da2dde8Sshadow303 // map and verify card's BIOS to see whether this really is a Radeon 512*1da2dde8Sshadow303 // (as we need BIOS for further info we have to make sure we use the right one) 513*1da2dde8Sshadow303 status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri ) 514*1da2dde8Sshadow303 { 515*1da2dde8Sshadow303 char buffer[B_OS_NAME_LENGTH]; 516*1da2dde8Sshadow303 517*1da2dde8Sshadow303 sprintf(buffer, "%04X_%04X_%02X%02X%02X bios", 518*1da2dde8Sshadow303 pcii->vendor_id, pcii->device_id, 519*1da2dde8Sshadow303 pcii->bus, pcii->device, pcii->function); 520*1da2dde8Sshadow303 521*1da2dde8Sshadow303 // we only scan BIOS at legacy location in first MB; 522*1da2dde8Sshadow303 // using the PCI location would improve detection, especially 523*1da2dde8Sshadow303 // if multiple graphics cards are installed 524*1da2dde8Sshadow303 // BUT: BeOS uses the first graphics card it finds (sorted by 525*1da2dde8Sshadow303 // device name), thus you couldn't choose in BIOS which card 526*1da2dde8Sshadow303 // to use; checking the legacy location ensures that the card is 527*1da2dde8Sshadow303 // only detected if it's the primary card 528*1da2dde8Sshadow303 ri->bios_area = map_physical_memory( buffer, (void *)0xc0000, 529*1da2dde8Sshadow303 0x40000, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&ri->bios_ptr ); 530*1da2dde8Sshadow303 if( ri->bios_area < 0 ) 531*1da2dde8Sshadow303 return ri->bios_area; 532*1da2dde8Sshadow303 533*1da2dde8Sshadow303 ri->rom_ptr = Radeon_FindRom( ri ); 534*1da2dde8Sshadow303 535*1da2dde8Sshadow303 return ri->rom_ptr != NULL ? B_OK : B_ERROR; 536*1da2dde8Sshadow303 } 537*1da2dde8Sshadow303 538*1da2dde8Sshadow303 539*1da2dde8Sshadow303 // unmap card's BIOS 540*1da2dde8Sshadow303 void Radeon_UnmapBIOS( rom_info *ri ) 541*1da2dde8Sshadow303 { 542*1da2dde8Sshadow303 delete_area( ri->bios_area ); 543*1da2dde8Sshadow303 544*1da2dde8Sshadow303 ri->bios_ptr = ri->rom_ptr = NULL; 545*1da2dde8Sshadow303 } 546*1da2dde8Sshadow303 547*1da2dde8Sshadow303 548*1da2dde8Sshadow303 // get everything valuable from BIOS (BIOS must be mapped) 549*1da2dde8Sshadow303 status_t Radeon_ReadBIOSData( device_info *di ) 550*1da2dde8Sshadow303 { 551*1da2dde8Sshadow303 shared_info dummy_si; 552*1da2dde8Sshadow303 status_t result = B_OK; 553*1da2dde8Sshadow303 554*1da2dde8Sshadow303 // give Radeon_MapDevice something to play with 555*1da2dde8Sshadow303 di->si = &dummy_si; 556*1da2dde8Sshadow303 557*1da2dde8Sshadow303 // don't map frame buffer - we don't know its proper size yet! 558*1da2dde8Sshadow303 result = Radeon_MapDevice( di, true ); 559*1da2dde8Sshadow303 if( result < 0 ) 560*1da2dde8Sshadow303 goto err1; 561*1da2dde8Sshadow303 562*1da2dde8Sshadow303 Radeon_GetPLLInfo( di ); 563*1da2dde8Sshadow303 Radeon_GetBIOSMon( di ); 564*1da2dde8Sshadow303 Radeon_DetectRAM( di ); 565*1da2dde8Sshadow303 566*1da2dde8Sshadow303 Radeon_UnmapDevice( di ); 567*1da2dde8Sshadow303 568*1da2dde8Sshadow303 err1: 569*1da2dde8Sshadow303 di->si = NULL; 570*1da2dde8Sshadow303 571*1da2dde8Sshadow303 return result; 572*1da2dde8Sshadow303 } 573