📄 bios.c
字号:
/* Copyright (c) 2002, Thomas Kurschel Part of Radeon kernel driver BIOS detection and retrieval of vital data Most of this data should be gathered directly, especially monitor detection should be done on demand so not all monitors need to be connected during boot*/#include "radeon_driver.h"#include "../shared/mmio.h"#include "../regs/bios_regs.h"#include "../regs/config_regs.h"#include "../regs/memcntrl_regs.h"#include "../regs/fp_regs.h"#include "../regs/crtc_regs.h"#include "../shared/radeon_bios.h"#include "../common/utils.h"#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};// find address of ROM;// this code is really nasty as maintaining the radeon signatures// is almost impossible (the signatures provided by ATI are always out-dated);// further, if there is more then one card built into the computer, we// may detect the wrong BIOS! // we have two possible solutions:// 1. use the PCI location as stored in BIOS// 2. verify the IO-base address as stored in BIOS// I have no clue how these values are _written_ into the BIOS, and// unfortunately, every BIOS does the detection in a different way,// so I'm not sure which is the _right_ way of doing itstatic char *Radeon_FindRom( rom_info *ri ){ uint32 segstart; uint8 *rom_base; char *rom; int i,j; for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) { bool found = false; // find ROM rom_base = ri->bios_ptr + segstart - 0xc0000; if( rom_base[0] != 0x55 || rom_base[1] != 0xaa ) continue; // find signature of ATI rom = rom_base; 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, rom_base + i, strlen( ati_rom_sig )) == 0 ) { found = true; break; } } } 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; SHOW_INFO( 2, "found ROM @0x%lx", segstart ); return rom_base; } SHOW_INFO0( 2, "no ROM found" ); return NULL;}// PLL info is stored in ROM, probably it's too easy to replace it// and thus they produce cards with different timingsstatic void Radeon_GetPLLInfo( device_info *di ){ uint8 *bios_header; 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 )); 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", di->pll.ref_freq, di->pll.ref_div, di->pll.xclk, di->pll.min_pll_freq, di->pll.max_pll_freq );}/*const char *Mon2Str[] = { "N/C", "CRT", "CRT", "Laptop flatpanel", "DVI (flatpanel)", "secondary DVI (flatpanel) - unsupported", "Composite TV", "S-Video out"};*//*// ask BIOS what kind of monitor is connected to each portstatic void Radeon_GetMonType( device_info *di ){ unsigned int tmp; SHOW_FLOW0( 3, "" ); di->disp_type[0] = di->disp_type[1] = dt_none; if (di->has_crtc2) { tmp = INREG( di->regs, RADEON_BIOS_4_SCRATCH ); // ordering of "if"s is important as multiple // devices can be concurrently connected to one port // (like both a CRT and a TV) // primary port // having flat-panel support is most important if (tmp & 0x08) di->disp_type[0] = dt_dvi; else if (tmp & 0x4) di->disp_type[0] = dt_lvds; else if (tmp & 0x200) di->disp_type[0] = dt_tv_crt; else if (tmp & 0x10) di->disp_type[0] = dt_ctv; else if (tmp & 0x20) di->disp_type[0] = dt_stv; // secondary port // having TV-Out support is more important then CRT support // (CRT gets signal anyway) if (tmp & 0x1000) di->disp_type[1] = dt_ctv; else if (tmp & 0x2000) di->disp_type[1] = dt_stv; else if (tmp & 0x2) di->disp_type[1] = dt_crt; else if (tmp & 0x800) di->disp_type[1] = dt_dvi_ext; else if (tmp & 0x400) // this is unlikely - I only know about one LVDS unit di->disp_type[1] = dt_lvds; } else { // regular Radeon // TBD: no TV-Out detection di->disp_type[0] = dt_none; tmp = INREG( di->regs, RADEON_FP_GEN_CNTL); if( tmp & RADEON_FP_EN_TMDS ) di->disp_type[0] = dt_dvi; else di->disp_type[0] = dt_crt; } SHOW_INFO( 1, "BIOS reports %s on primary and %s on secondary port", Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]); // remove unsupported devices if( di->disp_type[0] >= dt_dvi_ext ) di->disp_type[0] = dt_none; if( di->disp_type[1] >= dt_dvi_ext ) di->disp_type[1] = dt_none; // HACK: overlays can only be shown on first CRTC; // if there's nothing on first port, connect // second port to first CRTC (proper signal routing // is hopefully done by BIOS) if( di->has_crtc2 ) { if( di->disp_type[0] == dt_none && di->disp_type[1] == dt_crt ) { di->disp_type[0] = dt_crt; di->disp_type[1] = dt_none; } } SHOW_INFO( 1, "Effective routing: %s on primary and %s on secondary port", Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);}*/// get flat panel info (does only make sense for Laptops// with integrated display, but looking for it doesn't hurt,// who knows which strange kind of combination is out there?)static bool Radeon_GetBIOSDFPInfo( device_info *di ){ uint8 *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); fpi_offset = *(uint16 *)(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; // 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -