Convert Thomas's radeon driver to our build structure.
Added some card ids. Still needs work to properly enable logging and extra settings. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6982 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bbd8e7fbd9
commit
1da2dde8c2
37
src/add-ons/kernel/drivers/graphics/radeon/Jamfile
Normal file
37
src/add-ons/kernel/drivers/graphics/radeon/Jamfile
Normal file
@ -0,0 +1,37 @@
|
||||
SubDir OBOS_TOP src add-ons kernel drivers graphics radeon ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics radeon ] ;
|
||||
|
||||
R5KernelAddon radeon.driver : kernel drivers bin :
|
||||
driver.c
|
||||
agp.c
|
||||
bios.c
|
||||
detect.c
|
||||
dma.c
|
||||
global_data.c
|
||||
init.c
|
||||
irq.c
|
||||
memmgr.c
|
||||
;
|
||||
|
||||
#Package openbeos-radeon-cvs :
|
||||
# README.html UPDATE.html ;
|
||||
Package openbeos-radeon-cvs :
|
||||
radeon.driver :
|
||||
boot home config add-ons kernel drivers bin ;
|
||||
Package openbeos-radeon-cvs :
|
||||
<kernel!drivers!dev!graphics>radeon.driver :
|
||||
boot home config add-ons kernel drivers dev graphics ;
|
||||
#Package openbeos-radeon-cvs :
|
||||
# radeon.settings :
|
||||
# boot home config settings kernel drivers ;
|
||||
|
||||
# Link to kernel/drivers/dev/graphics
|
||||
{
|
||||
local dir = [ FDirName $(OBOS_ADDON_DIR) kernel drivers dev graphics ] ;
|
||||
local instDriver = <kernel!drivers!dev!graphics>radeon.driver ;
|
||||
MakeLocate $(instDriver) : $(dir) ;
|
||||
RelSymLink $(instDriver) : radeon.driver ;
|
||||
}
|
||||
|
213
src/add-ons/kernel/drivers/graphics/radeon/agp.c
Normal file
213
src/add-ons/kernel/drivers/graphics/radeon/agp.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
AGP fix. Some motherboard BIOSes enable FastWrite even
|
||||
though the graphics card doesn't support it. Here, we'll
|
||||
fix that (hopefully it is generic enough).
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_driver.h"
|
||||
|
||||
|
||||
// missing PCI definitions
|
||||
#define PCI_status_cap_list 0x10 /* Support Capability List */
|
||||
|
||||
#define PCI_header_type_normal 0
|
||||
#define PCI_header_type_bridge 1
|
||||
//#define PCI_header_type_cardbus 2
|
||||
|
||||
#define PCI_capability_list 0x34 /* Offset of first capability list entry */
|
||||
#define PCI_cb_capability_list 0x14
|
||||
|
||||
#define PCI_cap_list_id 0 /* Capability ID */
|
||||
#define PCI_cap_id_pm 0x01 /* Power Management */
|
||||
#define PCI_cap_id_agp 0x02 /* Accelerated Graphics Port */
|
||||
#define PCI_cap_id_vpd 0x03 /* Vital Product Data */
|
||||
#define PCI_cap_id_slotid 0x04 /* Slot Identification */
|
||||
#define PCI_cap_id_msi 0x05 /* Message Signalled Interrupts */
|
||||
#define PCI_cap_id_chswp 0x06 /* CompactPCI HotSwap */
|
||||
#define PCI_cap_list_next 1 /* Next capability in the list */
|
||||
#define PCI_cap_flags 2 /* Capability defined flags (16 bits) */
|
||||
#define PCI_cap_sizeof 4
|
||||
|
||||
|
||||
#define PCI_agp_status 4 /* Status register */
|
||||
#define PCI_agp_status_rq_mask 0xff000000 /* Maximum number of requests - 1 */
|
||||
#define PCI_agp_status_sba 0x0200 /* Sideband addressing supported */
|
||||
#define PCI_agp_status_64bit 0x0020 /* 64-bit addressing supported */
|
||||
#define PCI_agp_status_fw 0x0010 /* FW transfers supported */
|
||||
#define PCI_agp_status_rate4 0x0004 /* 4x transfer rate supported */
|
||||
#define PCI_agp_status_rate2 0x0002 /* 2x transfer rate supported */
|
||||
#define PCI_agp_status_rate1 0x0001 /* 1x transfer rate supported */
|
||||
|
||||
#define PCI_agp_command 8 /* Control register */
|
||||
#define PCI_agp_command_rq_mask 0xff000000 /* Master: Maximum number of requests */
|
||||
#define PCI_agp_command_sba 0x0200 /* Sideband addressing enabled */
|
||||
#define PCI_agp_command_agp 0x0100 /* Allow processing of AGP transactions */
|
||||
#define PCI_agp_command_64bit 0x0020 /* Allow processing of 64-bit addresses */
|
||||
#define PCI_agp_command_fw 0x0010 /* Force FW transfers */
|
||||
#define PCI_agp_command_rate4 0x0004 /* Use 4x rate */
|
||||
#define PCI_agp_command_rate2 0x0002 /* Use 2x rate */
|
||||
#define PCI_agp_command_rate1 0x0001 /* Use 1x rate */
|
||||
|
||||
|
||||
|
||||
// helper macros for easier PCI access
|
||||
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
|
||||
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
|
||||
|
||||
int find_capability( pci_info *pcii, uint8 capability );
|
||||
void Radeon_Fix_AGP( void );
|
||||
|
||||
|
||||
// show AGP capabilities
|
||||
static void show_agp_status( uint32 status )
|
||||
{
|
||||
SHOW_FLOW( 3, "Status (%08lx): %s%s%s%s%s%s", status,
|
||||
(status & PCI_agp_status_sba) != 0 ? "Sideband addressing " : "",
|
||||
(status & PCI_agp_status_64bit) != 0 ? "64-bit " : "",
|
||||
(status & PCI_agp_status_fw) != 0 ? "FastWrite " : "",
|
||||
(status & PCI_agp_status_rate4) != 0 ? "4x " : "",
|
||||
(status & PCI_agp_status_rate2) != 0 ? "2x " : "",
|
||||
(status & PCI_agp_status_rate1) != 0 ? "1x " : "" );
|
||||
}
|
||||
|
||||
|
||||
// show AGP settings
|
||||
static void show_agp_command( uint32 command )
|
||||
{
|
||||
SHOW_FLOW( 3, "Command (%08lx): %s%s%s%s%s%s%s", command,
|
||||
(command & PCI_agp_command_sba) != 0 ? "Sideband addressing " : "",
|
||||
(command & PCI_agp_command_agp) != 0 ? "AGP-Enabled " : "AGP-Disabled ",
|
||||
(command & PCI_agp_command_64bit) != 0 ? "64-bit " : "",
|
||||
(command & PCI_agp_command_fw) != 0 ? "FastWrite " : "",
|
||||
(command & PCI_agp_command_rate4) != 0 ? "4x " : "",
|
||||
(command & PCI_agp_command_rate2) != 0 ? "2x " : "",
|
||||
(command & PCI_agp_command_rate1) != 0 ? "1x " : "" );
|
||||
}
|
||||
|
||||
|
||||
// find PCI capability
|
||||
int find_capability( pci_info *pcii, uint8 capability )
|
||||
{
|
||||
int try_count;
|
||||
uint16 status;
|
||||
uint8 pos;
|
||||
|
||||
// check whether PCI capabilities are supported at all
|
||||
status = get_pci( PCI_status, 2 );
|
||||
|
||||
if( (status & PCI_status_cap_list) == 0 )
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
SHOW_FLOW0( 3, "Device supports capabilities" );
|
||||
|
||||
// get offset of first capability in list
|
||||
switch( pcii->header_type & PCI_header_type_mask ) {
|
||||
case PCI_header_type_normal:
|
||||
case PCI_header_type_bridge:
|
||||
pos = get_pci( PCI_capability_list, 1 );
|
||||
break;
|
||||
case PCI_header_type_cardbus:
|
||||
pos = get_pci( PCI_cb_capability_list, 1 );
|
||||
break;
|
||||
default:
|
||||
SHOW_FLOW( 3, "Unknown type (%x)", pcii->header_type & PCI_header_type_mask );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// search for whished capability in linked list
|
||||
for( try_count = 48; try_count > 0 && pos >= 0x40; --try_count ) {
|
||||
uint8 id;
|
||||
|
||||
pos &= ~3;
|
||||
|
||||
id = get_pci( pos + PCI_cap_list_id, 1 );
|
||||
if( id == 0xff )
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
if( id == capability ) {
|
||||
SHOW_FLOW( 3, "Found capability %d", capability );
|
||||
return pos;
|
||||
}
|
||||
|
||||
SHOW_FLOW( 3, "Ignored capability %d", id );
|
||||
|
||||
pos = get_pci( pos + PCI_cap_list_next, 1 );
|
||||
}
|
||||
|
||||
return B_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
// fix invalid AGP settings
|
||||
void Radeon_Fix_AGP()
|
||||
{
|
||||
long pci_index;
|
||||
pci_info pci_data, *pcii;
|
||||
|
||||
uint32 common_caps =
|
||||
PCI_agp_status_sba | PCI_agp_status_64bit | PCI_agp_status_fw |
|
||||
PCI_agp_status_rate4 | PCI_agp_status_rate2 | PCI_agp_status_rate1;
|
||||
uint32 read_queue_depth = PCI_agp_status_rq_mask;
|
||||
|
||||
SHOW_FLOW0( 4, "Composing common feature list" );
|
||||
|
||||
// only required to make get_pci/set_pci working
|
||||
pcii = &pci_data;
|
||||
|
||||
// find common feature set
|
||||
for( pci_index = 0;
|
||||
(*pci_bus->get_nth_pci_info)(pci_index, &pci_data) == B_NO_ERROR;
|
||||
++pci_index )
|
||||
{
|
||||
int offset;
|
||||
|
||||
SHOW_FLOW( 3, "Checking bus %d, device %d, function %d (vendor_id=%04x, device_id=%04x):",
|
||||
pcii->bus, pcii->device, pcii->function,
|
||||
pcii->vendor_id, pcii->device_id );
|
||||
|
||||
offset = find_capability( pcii, PCI_cap_id_agp );
|
||||
|
||||
if( offset > 0 ) {
|
||||
uint32 agp_status, agp_command;
|
||||
|
||||
agp_status = get_pci( offset + PCI_agp_status, 4 );
|
||||
agp_command = get_pci( offset + PCI_agp_command, 4 );
|
||||
|
||||
SHOW_FLOW( 3, "bus %d, device %d, function %d (vendor_id=%04x, device_id=%04x):",
|
||||
pcii->bus, pcii->device, pcii->function,
|
||||
pcii->vendor_id, pcii->device_id );
|
||||
show_agp_status( agp_status );
|
||||
show_agp_command( agp_command );
|
||||
|
||||
common_caps &= agp_status;
|
||||
read_queue_depth = min( read_queue_depth, agp_status & PCI_agp_status_rq_mask );
|
||||
}
|
||||
}
|
||||
|
||||
SHOW_FLOW0( 3, "Combined:" );
|
||||
show_agp_command( common_caps );
|
||||
|
||||
// choose features that all devices support
|
||||
for( pci_index = 0;
|
||||
(*pci_bus->get_nth_pci_info)(pci_index, &pci_data) == B_NO_ERROR;
|
||||
++pci_index )
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = find_capability( pcii, PCI_cap_id_agp );
|
||||
|
||||
if( offset > 0 ) {
|
||||
SHOW_FLOW( 3, "Modifying bus %d, device %d, function %d (vendor_id=%04x, device_id=%04x):",
|
||||
pcii->bus, pcii->device, pcii->function,
|
||||
pcii->vendor_id, pcii->device_id );
|
||||
|
||||
set_pci( offset + PCI_agp_command, 4, common_caps | read_queue_depth );
|
||||
}
|
||||
}
|
||||
}
|
572
src/add-ons/kernel/drivers/graphics/radeon/bios.c
Normal file
572
src/add-ons/kernel/drivers/graphics/radeon/bios.c
Normal file
@ -0,0 +1,572 @@
|
||||
/*
|
||||
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 <mmio.h>
|
||||
#include <bios_regs.h>
|
||||
#include <config_regs.h>
|
||||
#include <memcntrl_regs.h>
|
||||
#include <fp_regs.h>
|
||||
#include <crtc_regs.h>
|
||||
#include <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[] = {
|
||||
"RG6", // r200
|
||||
"RADEON", // r100
|
||||
"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
|
||||
"RV100", // rv100
|
||||
"M7", // m7
|
||||
"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
|
||||
"M9" // guess: m9
|
||||
};
|
||||
|
||||
void Radeon_DetectRAM( device_info *di );
|
||||
|
||||
|
||||
// find address of ROM
|
||||
static char *Radeon_FindRom( rom_info *ri )
|
||||
{
|
||||
uint32 segstart;
|
||||
char *rom_base;
|
||||
char *rom;
|
||||
int stage;
|
||||
int i,j;
|
||||
|
||||
for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) {
|
||||
stage = 1;
|
||||
|
||||
// find ROM
|
||||
rom_base = ri->bios_ptr + segstart - 0xc0000;
|
||||
|
||||
if( *rom_base == 0x55 && ((*(rom_base + 1)) & 0xff) == 0xaa )
|
||||
stage = 2;
|
||||
|
||||
if (stage != 2)
|
||||
continue;
|
||||
|
||||
// find signature of ATI
|
||||
rom = rom_base;
|
||||
|
||||
for( i = 0; i < 128 - (int)strlen( ati_rom_sig ) && stage != 3; i++ ) {
|
||||
if( ati_rom_sig[0] == *rom ) {
|
||||
if( strncmp(ati_rom_sig, rom, strlen( ati_rom_sig )) == 0 )
|
||||
stage = 3;
|
||||
}
|
||||
rom++;
|
||||
}
|
||||
|
||||
if( stage != 3 )
|
||||
continue;
|
||||
|
||||
// find signature of card
|
||||
rom = rom_base;
|
||||
|
||||
for( i = 0; (i < 512) && (stage != 4); i++ ) {
|
||||
for( j = 0; j < (int)sizeof( radeon_sig ) / (int)sizeof( radeon_sig[0] ); j++ ) {
|
||||
if( radeon_sig[j][0] == *rom ) {
|
||||
if( strncmp( radeon_sig[j], rom, strlen( radeon_sig[j] )) == 0 ) {
|
||||
SHOW_INFO( 2, "Signature: %s", radeon_sig[j] );
|
||||
stage = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rom++;
|
||||
}
|
||||
|
||||
if( stage != 4 )
|
||||
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 to easily replace it
|
||||
// and thus produce cards with different timings
|
||||
static 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 - unsupported",
|
||||
"S-Video out - unsupported"
|
||||
};
|
||||
|
||||
// ask BIOS what kind of monitor is connected to each port
|
||||
static 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 are multiple
|
||||
// devices can be concurrently connected to one port
|
||||
// (like both a CRT and a TV)
|
||||
|
||||
// primary port
|
||||
if (tmp & 0x08)
|
||||
di->disp_type[0] = dt_dvi_1;
|
||||
else if (tmp & 0x4)
|
||||
di->disp_type[0] = dt_lvds;
|
||||
else if (tmp & 0x200)
|
||||
di->disp_type[0] = dt_crt_1;
|
||||
else if (tmp & 0x10)
|
||||
di->disp_type[0] = dt_ctv;
|
||||
else if (tmp & 0x20)
|
||||
di->disp_type[0] = dt_stv;
|
||||
|
||||
// secondary port
|
||||
if (tmp & 0x2)
|
||||
di->disp_type[1] = dt_crt_2;
|
||||
else if (tmp & 0x800)
|
||||
di->disp_type[1] = dt_dvi_2;
|
||||
else if (tmp & 0x400)
|
||||
// this is unlikely - I only know about one LVDS unit
|
||||
di->disp_type[1] = dt_lvds;
|
||||
else if (tmp & 0x1000)
|
||||
di->disp_type[1] = dt_ctv;
|
||||
else if (tmp & 0x2000)
|
||||
di->disp_type[1] = dt_stv;
|
||||
} else {
|
||||
// regular Radeon
|
||||
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_1;
|
||||
else
|
||||
di->disp_type[0] = dt_crt_1;
|
||||
}
|
||||
|
||||
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_2 )
|
||||
di->disp_type[0] = dt_none;
|
||||
if( di->disp_type[1] >= dt_dvi_2 )
|
||||
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_2 ) {
|
||||
di->disp_type[0] = dt_crt_1;
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// try to reverse engineer DFP specification from
|
||||
// timing currently set up in graphics cards registers
|
||||
// (effectively, we hope that BIOS has set it up correctly
|
||||
// and noone has messed registers up yet; let's pray)
|
||||
static void Radeon_RevEnvDFPSize( device_info *di )
|
||||
{
|
||||
vuint8 *regs = di->regs;
|
||||
/* uint32 r;
|
||||
|
||||
// take a look at flat_panel.c of the accelerant how register values
|
||||
// are calculated - this is the inverse function
|
||||
r = INREG( regs, RADEON_FP_VERT_STRETCH );
|
||||
if( (r & RADEON_VERT_STRETCH_BLEND) == 0 ) {
|
||||
di->fp_info.panel_yres =
|
||||
((r & RADEON_VERT_PANEL_SIZE) >> RADEON_VERT_PANEL_SHIFT) + 1;
|
||||
} else {
|
||||
uint32 v_total = (INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP )
|
||||
>> RADEON_FP_CRTC_V_DISP_SHIFT) + 1;
|
||||
SHOW_INFO( 2, "stretched mode: v_total=%d", v_total );
|
||||
di->fp_info.panel_yres =
|
||||
(v_total * FIX_SCALE * RADEON_VERT_STRETCH_RATIO_MAX /
|
||||
(r & RADEON_VERT_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT;
|
||||
// seems to be a BIOS bug - vertical size is 1 point too small
|
||||
// (checked by re-calculating stretch factor)
|
||||
++di->fp_info.panel_yres;
|
||||
}
|
||||
|
||||
r = INREG( regs, RADEON_FP_HORZ_STRETCH );
|
||||
if( (r & RADEON_HORZ_STRETCH_BLEND) == 0 ) {
|
||||
di->fp_info.panel_xres =
|
||||
(((r & RADEON_HORZ_PANEL_SIZE) >> RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
|
||||
} else {
|
||||
uint32 h_total = ((INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP )
|
||||
>> RADEON_FP_CRTC_H_DISP_SHIFT) + 1) * 8;
|
||||
SHOW_INFO( 2, "stretched mode: h_total=%d", h_total );
|
||||
di->fp_info.panel_xres =
|
||||
(h_total * FIX_SCALE * RADEON_HORZ_STRETCH_RATIO_MAX /
|
||||
(r & RADEON_HORZ_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT;
|
||||
}*/
|
||||
|
||||
di->fp_info.panel_yres =
|
||||
((INREG( regs, RADEON_FP_VERT_STRETCH ) & RADEON_VERT_PANEL_SIZE)
|
||||
>> RADEON_VERT_PANEL_SHIFT) + 1;
|
||||
|
||||
di->fp_info.panel_xres =
|
||||
(((INREG( regs, RADEON_FP_HORZ_STRETCH ) & RADEON_HORZ_PANEL_SIZE)
|
||||
>> RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
|
||||
|
||||
SHOW_INFO( 2, "detected panel size from registers: %dx%d",
|
||||
di->fp_info.panel_xres, di->fp_info.panel_yres);
|
||||
}
|
||||
|
||||
|
||||
// once more for getting precise timing
|
||||
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 );
|
||||
// the magic "4" was found by trial and error and probably stems from fudge (see crtc.c)
|
||||
a = (r & RADEON_FP_CRTC_H_TOTAL_MASK)/* + 4*/;
|
||||
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/* - 1*/;
|
||||
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);
|
||||
// TBD: this seems to be wrong
|
||||
// (BIOS tells 112, this calculation leads to 24!)
|
||||
di->fp_info.h_sync_width *= 8;
|
||||
|
||||
r = INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP );
|
||||
a = (r & RADEON_FP_CRTC_V_TOTAL_MASK)/* + 1*/;
|
||||
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)/* + 1*/;
|
||||
|
||||
// standard CRTC
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// get everything in terms of monitors connected to the card
|
||||
static void Radeon_GetBIOSMon( device_info *di )
|
||||
{
|
||||
Radeon_GetMonType( di );
|
||||
|
||||
// reset all Flat Panel Info;
|
||||
// it gets filled out step by step, and this way we know what's still missing
|
||||
memset( &di->fp_info, 0, sizeof( di->fp_info ));
|
||||
|
||||
// we assume that the only fp port is combined with standard port 0
|
||||
di->fp_info.disp_type = di->disp_type[0];
|
||||
|
||||
if( di->disp_type[0] == dt_dvi_1 || di->disp_type[0] == dt_lvds )
|
||||
{
|
||||
// there is a flat panel - get info about it
|
||||
Radeon_GetBIOSDFPInfo( di );
|
||||
|
||||
// if BIOS doesn't know, ask the registers
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// detect amount of graphics memory
|
||||
void Radeon_DetectRAM( device_info *di )
|
||||
{
|
||||
vuint8 *regs = di->regs;
|
||||
|
||||
di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK;
|
||||
|
||||
// some production boards of m6 will return 0 if it's 8 MB
|
||||
if( di->local_mem_size == 0 )
|
||||
di->local_mem_size = 8 * 1024 *1024;
|
||||
|
||||
switch( INREG( regs, RADEON_MEM_SDRAM_MODE_REG ) & RADEON_MEM_CFG_TYPE_MASK ) {
|
||||
case RADEON_MEM_CFG_SDR:
|
||||
// SDR SGRAM (2:1)
|
||||
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;
|
||||
break;
|
||||
|
||||
case RADEON_MEM_CFG_DDR:
|
||||
// DDR SGRAM
|
||||
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;
|
||||
break;
|
||||
|
||||
// only one bit, so there's no default
|
||||
}
|
||||
|
||||
SHOW_INFO( 1, "%ld MB %s found", di->local_mem_size / 1024 / 1024,
|
||||
di->ram_type );
|
||||
|
||||
if( di->local_mem_size > 64 * 1024 * 1024 ) {
|
||||
di->local_mem_size = 64 * 1024 * 1024;
|
||||
|
||||
SHOW_INFO0( 1, "restricted to 64 MB" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// map and verify card's BIOS to see whether this really is a Radeon
|
||||
// (as we need BIOS for further info we have to make sure we use the right one)
|
||||
status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri )
|
||||
{
|
||||
char buffer[B_OS_NAME_LENGTH];
|
||||
|
||||
sprintf(buffer, "%04X_%04X_%02X%02X%02X bios",
|
||||
pcii->vendor_id, pcii->device_id,
|
||||
pcii->bus, pcii->device, pcii->function);
|
||||
|
||||
// we only scan BIOS at legacy location in first MB;
|
||||
// using the PCI location would improve detection, especially
|
||||
// if multiple graphics cards are installed
|
||||
// BUT: BeOS uses the first graphics card it finds (sorted by
|
||||
// device name), thus you couldn't choose in BIOS which card
|
||||
// to use; checking the legacy location ensures that the card is
|
||||
// only detected if it's the primary card
|
||||
ri->bios_area = map_physical_memory( buffer, (void *)0xc0000,
|
||||
0x40000, 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 );
|
||||
|
||||
return ri->rom_ptr != NULL ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// unmap card's BIOS
|
||||
void Radeon_UnmapBIOS( rom_info *ri )
|
||||
{
|
||||
delete_area( ri->bios_area );
|
||||
|
||||
ri->bios_ptr = ri->rom_ptr = NULL;
|
||||
}
|
||||
|
||||
|
||||
// get everything valuable from BIOS (BIOS must be mapped)
|
||||
status_t Radeon_ReadBIOSData( device_info *di )
|
||||
{
|
||||
shared_info dummy_si;
|
||||
status_t result = B_OK;
|
||||
|
||||
// give Radeon_MapDevice something to play with
|
||||
di->si = &dummy_si;
|
||||
|
||||
// don't map frame buffer - we don't know its proper size yet!
|
||||
result = Radeon_MapDevice( di, true );
|
||||
if( result < 0 )
|
||||
goto err1;
|
||||
|
||||
Radeon_GetPLLInfo( di );
|
||||
Radeon_GetBIOSMon( di );
|
||||
Radeon_DetectRAM( di );
|
||||
|
||||
Radeon_UnmapDevice( di );
|
||||
|
||||
err1:
|
||||
di->si = NULL;
|
||||
|
||||
return result;
|
||||
}
|
375
src/add-ons/kernel/drivers/graphics/radeon/detect.c
Normal file
375
src/add-ons/kernel/drivers/graphics/radeon/detect.c
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Graphics card detection
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_driver.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// this table is gathered from different sources
|
||||
// and may even contain some wrong entries
|
||||
#define VENDOR_ID_ATI 0x1002
|
||||
|
||||
// R100
|
||||
#define DEVICE_ID_RADEON_QD 0x5144
|
||||
#define DEVICE_ID_RADEON_QE 0x5145
|
||||
#define DEVICE_ID_RADEON_QF 0x5146
|
||||
#define DEVICE_ID_RADEON_QG 0x5147
|
||||
|
||||
// RV100
|
||||
#define DEVICE_ID_RADEON_QY 0x5159
|
||||
#define DEVICE_ID_RADEON_QZ 0x515a
|
||||
|
||||
// M6
|
||||
#define DEVICE_ID_RADEON_LY 0x4c59
|
||||
#define DEVICE_ID_RADEON_LZ 0x4c5a
|
||||
|
||||
// RV200
|
||||
#define DEVICE_ID_RADEON_QW 0x5157
|
||||
#define DEVICE_ID_RADEON_QX 0x5158
|
||||
|
||||
// R200 mobility
|
||||
#define DEVICE_ID_RADEON_LW 0x4c57
|
||||
#define DEVICE_ID_RADEON_LX 0x4c58
|
||||
|
||||
// R200
|
||||
#define DEVICE_ID_RADEON_QH 0x5148
|
||||
#define DEVICE_ID_RADEON_QI 0x5149
|
||||
#define DEVICE_ID_RADEON_QJ 0x514a
|
||||
#define DEVICE_ID_RADEON_QK 0x514b
|
||||
#define DEVICE_ID_RADEON_QL 0x514c
|
||||
#define DEVICE_ID_RADEON_QM 0x514d
|
||||
|
||||
#define DEVICE_ID_RADEON_Qh 0x5168
|
||||
#define DEVICE_ID_RADEON_Qi 0x5169
|
||||
#define DEVICE_ID_RADEON_Qj 0x516a
|
||||
#define DEVICE_ID_RADEON_Qk 0x516b
|
||||
|
||||
#define DEVICE_ID_RADEON_BB 0x4242
|
||||
|
||||
// RV250
|
||||
#define DEVICE_ID_RADEON_Id 0x4964
|
||||
#define DEVICE_ID_RADEON_Ie 0x4965
|
||||
#define DEVICE_ID_RADEON_If 0x4966
|
||||
#define DEVICE_ID_RADEON_Ig 0x4967
|
||||
|
||||
// M9
|
||||
#define DEVICE_ID_RADEON_Ld 0x4c64
|
||||
#define DEVICE_ID_RADEON_Le 0x4c65
|
||||
#define DEVICE_ID_RADEON_Lf 0x4c66
|
||||
#define DEVICE_ID_RADEON_Lg 0x4c67
|
||||
|
||||
// RV280
|
||||
#define DEVICE_ID_RADEON_Ya_ 0x5960
|
||||
#define DEVICE_ID_RADEON_Ya 0x5961
|
||||
#define DEVICE_ID_RADEON_Yd 0x5964
|
||||
|
||||
// r300
|
||||
#define DEVICE_ID_RADEON_ND 0x4e44
|
||||
#define DEVICE_ID_RADEON_NE 0x4e45
|
||||
#define DEVICE_ID_RADEON_NF 0x4e46
|
||||
#define DEVICE_ID_RADEON_NG 0x4e47
|
||||
|
||||
// r300-4P
|
||||
#define DEVICE_ID_RADEON_AD 0x4144
|
||||
#define DEVICE_ID_RADEON_AE 0x4145
|
||||
#define DEVICE_ID_RADEON_AF 0x4146
|
||||
#define DEVICE_ID_RADEON_AG 0x4147
|
||||
|
||||
// rv350
|
||||
#define DEVICE_ID_RADEON_AP 0x4150
|
||||
#define DEVICE_ID_RADEON_AQ 0x4151
|
||||
#define DEVICE_ID_RADEON_NO 0x4e50
|
||||
#define DEVICE_ID_RADEON_NS 0x4e54
|
||||
|
||||
// rv360
|
||||
#define DEVICE_ID_RADEON_AR 0x4152
|
||||
|
||||
// r350
|
||||
#define DEVICE_ID_RADEON_AH 0x4148
|
||||
#define DEVICE_ID_RADEON_NH 0x4e48
|
||||
#define DEVICE_ID_RADEON_NI 0x4e49
|
||||
|
||||
// r360
|
||||
#define DEVICE_ID_RADEON_NJ 0x4e4a
|
||||
|
||||
#define DEVICE_ID_IGP320M 0x4336
|
||||
|
||||
typedef struct {
|
||||
uint16 device_id;
|
||||
radeon_type asic;
|
||||
char *name;
|
||||
} RadeonDevice;
|
||||
|
||||
// list of supported devices
|
||||
RadeonDevice radeon_device_list[] = {
|
||||
// original Radeons, now called r100
|
||||
{ DEVICE_ID_RADEON_QD, rt_r100, "Radeon 7200 / Radeon / ALL-IN-WONDER Radeon" },
|
||||
{ DEVICE_ID_RADEON_QE, rt_r100, "Radeon QE" },
|
||||
{ DEVICE_ID_RADEON_QF, rt_r100, "Radeon QF" },
|
||||
{ DEVICE_ID_RADEON_QG, rt_r100, "Radeon QG" },
|
||||
|
||||
// Radeon VE (low-cost, dual CRT, no TCL), now called RV100
|
||||
{ DEVICE_ID_RADEON_QY, rt_ve, "Radeon 7000 / Radeon VE" },
|
||||
{ DEVICE_ID_RADEON_QZ, rt_ve, "Radeon QZ VE" },
|
||||
|
||||
// mobility version of original Radeon (based on VE), now called M6
|
||||
{ DEVICE_ID_RADEON_LY, rt_m6, "Radeon Mobility" },
|
||||
{ DEVICE_ID_RADEON_LZ, rt_m6, "Radeon Mobility M6 LZ" },
|
||||
|
||||
// RV200 (dual CRT)
|
||||
{ DEVICE_ID_RADEON_QW, rt_rv200, "Radeon 7500 / ALL-IN-WONDER Radeon 7500" },
|
||||
{ DEVICE_ID_RADEON_QX, rt_rv200, "Radeon 7500 QX" },
|
||||
|
||||
// R200 mobility (based on RV200)
|
||||
{ DEVICE_ID_RADEON_LW, rt_m7, "Radeon Mobility 7500" },
|
||||
{ DEVICE_ID_RADEON_LX, rt_m7, "Radeon Mobility 7500 GL" },
|
||||
|
||||
// R200
|
||||
{ DEVICE_ID_RADEON_QH, rt_r200, "Radeon 8500 QH" },
|
||||
{ DEVICE_ID_RADEON_QI, rt_r200, "Radeon 8500 QI" },
|
||||
{ DEVICE_ID_RADEON_QJ, rt_r200, "Radeon 8500 QJ" },
|
||||
{ DEVICE_ID_RADEON_QK, rt_r200, "Radeon 8500 QK" },
|
||||
{ DEVICE_ID_RADEON_QL, rt_r200, "Radeon 8500 / 8500LE / ALL-IN-WONDER Radeon 8500" },
|
||||
{ DEVICE_ID_RADEON_QM, rt_r200, "Radeon 9100" },
|
||||
|
||||
{ DEVICE_ID_RADEON_Qh, rt_r200, "Radeon 8500 Qh" },
|
||||
{ DEVICE_ID_RADEON_Qi, rt_r200, "Radeon 8500 Qi" },
|
||||
{ DEVICE_ID_RADEON_Qj, rt_r200, "Radeon 8500 Qj" },
|
||||
{ DEVICE_ID_RADEON_Qk, rt_r200, "Radeon 8500 Qk" },
|
||||
{ DEVICE_ID_RADEON_BB, rt_r200, "ALL-IN-Wonder Radeon 8500 DV" },
|
||||
|
||||
// RV250 (cut-down R200)
|
||||
{ DEVICE_ID_RADEON_Id, rt_rv250, "Radeon 9000 Id" },
|
||||
{ DEVICE_ID_RADEON_Ie, rt_rv250, "Radeon 9000 Ie" },
|
||||
{ DEVICE_ID_RADEON_If, rt_rv250, "Radeon 9000" },
|
||||
{ DEVICE_ID_RADEON_Ig, rt_rv250, "Radeon 9000 Ig" },
|
||||
|
||||
// M9 (based on rv250)
|
||||
{ DEVICE_ID_RADEON_Ld, rt_m9, "Radeon Mobility 9000 Ld" },
|
||||
{ DEVICE_ID_RADEON_Le, rt_m9, "Radeon Mobility 9000 Le" },
|
||||
{ DEVICE_ID_RADEON_Lf, rt_m9, "Radeon Mobility 9000 Lf" },
|
||||
{ DEVICE_ID_RADEON_Lg, rt_m9, "Radeon Mobility 9000 Lg" },
|
||||
|
||||
// RV280
|
||||
// the naming scheme can't properly handle this id
|
||||
{ DEVICE_ID_RADEON_Ya_, rt_rv250, "Radeon 9200" },
|
||||
{ DEVICE_ID_RADEON_Ya, rt_rv250, "Radeon 9200" },
|
||||
{ DEVICE_ID_RADEON_Yd, rt_rv250, "Radeon 9200 SE" },
|
||||
|
||||
// R300
|
||||
{ DEVICE_ID_RADEON_ND, rt_r300, "Radeon 9700 ND" },
|
||||
{ DEVICE_ID_RADEON_NE, rt_r300, "Radeon 9700 NE" },
|
||||
{ DEVICE_ID_RADEON_NF, rt_r300, "Radeon 9600 XT" },
|
||||
{ DEVICE_ID_RADEON_NG, rt_r300, "Radeon 9700 NG" },
|
||||
|
||||
{ DEVICE_ID_RADEON_AD, rt_r300, "Radeon 9700 AD" },
|
||||
{ DEVICE_ID_RADEON_AE, rt_r300, "Radeon 9700 AE" },
|
||||
{ DEVICE_ID_RADEON_AF, rt_r300, "Radeon 9700 AF" },
|
||||
{ DEVICE_ID_RADEON_AG, rt_r300, "Radeon 9700 AG" },
|
||||
|
||||
// RV350
|
||||
{ DEVICE_ID_RADEON_AP, rt_rv350, "Radeon 9600 AP" },
|
||||
{ DEVICE_ID_RADEON_AQ, rt_rv350, "Radeon 9600 AQ" },
|
||||
{ DEVICE_ID_RADEON_NO, rt_rv350, "Radeon Mobility 9600 Pro Turbo" },
|
||||
{ DEVICE_ID_RADEON_NS, rt_rv350, "Mobility FireGL T2" },
|
||||
|
||||
// RV360 (probably minor revision of rv350)
|
||||
{ DEVICE_ID_RADEON_AR, rt_rv360, "Radeon 9600 AR" },
|
||||
|
||||
// R350
|
||||
{ DEVICE_ID_RADEON_AH, rt_r350, "Radeon 9800 AH" },
|
||||
{ DEVICE_ID_RADEON_NH, rt_r350, "Radeon 9800 Pro NH" },
|
||||
{ DEVICE_ID_RADEON_NI, rt_r350, "Radeon 9800 NI" },
|
||||
|
||||
// R360 (probably minor revision of r350)
|
||||
{ DEVICE_ID_RADEON_NJ, rt_r360, "Radeon 9800 XT" },
|
||||
|
||||
{ DEVICE_ID_IGP320M, rt_ve, "Radeon IGP 320M" },
|
||||
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
// list of supported vendors (there aren't many ;)
|
||||
static struct {
|
||||
uint16 vendor_id;
|
||||
RadeonDevice *devices;
|
||||
} SupportedVendors[] = {
|
||||
{ VENDOR_ID_ATI, radeon_device_list },
|
||||
{ 0x0000, NULL }
|
||||
};
|
||||
|
||||
// check, whether there is *any* supported card plugged in
|
||||
bool Radeon_CardDetect( void )
|
||||
{
|
||||
long pci_index = 0;
|
||||
pci_info pcii;
|
||||
bool found_one = FALSE;
|
||||
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
|
||||
int vendor = 0;
|
||||
|
||||
while (SupportedVendors[vendor].vendor_id) {
|
||||
if (SupportedVendors[vendor].vendor_id == pcii.vendor_id) {
|
||||
RadeonDevice *devices = SupportedVendors[vendor].devices;
|
||||
|
||||
while (devices->device_id) {
|
||||
if (devices->device_id == pcii.device_id ) {
|
||||
rom_info ri;
|
||||
|
||||
if( Radeon_MapBIOS( &pcii, &ri ) == B_OK ) {
|
||||
Radeon_UnmapBIOS( &ri );
|
||||
|
||||
SHOW_INFO( 0, "found supported device pci index %ld, device 0x%04x/0x%04x",
|
||||
pci_index, pcii.vendor_id, pcii.device_id );
|
||||
found_one = TRUE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
devices++;
|
||||
}
|
||||
}
|
||||
vendor++;
|
||||
}
|
||||
|
||||
pci_index++;
|
||||
}
|
||||
SHOW_INFO0( 0, "no supported devices found" );
|
||||
|
||||
done:
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
|
||||
return (found_one ? B_OK : B_ERROR);
|
||||
}
|
||||
|
||||
// !extend this array whenever a new ASIC is a added!
|
||||
static bool has_crtc2[] =
|
||||
{
|
||||
false, // only original Radeons have one crtc only
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
};
|
||||
|
||||
static const char *asic_name[] =
|
||||
{
|
||||
"r100",
|
||||
"ve",
|
||||
"m6",
|
||||
"rv200",
|
||||
"m7",
|
||||
"r200",
|
||||
"rv250",
|
||||
"rv280",
|
||||
"m9",
|
||||
"r300",
|
||||
"r300_4p",
|
||||
"rv350",
|
||||
"rv360",
|
||||
"r350",
|
||||
"r360",
|
||||
};
|
||||
|
||||
// get next supported device
|
||||
static bool probeDevice( device_info *di )
|
||||
{
|
||||
int vendor;
|
||||
|
||||
/* if we match a supported vendor */
|
||||
for( vendor = 0; SupportedVendors[vendor].vendor_id; ++vendor ) {
|
||||
RadeonDevice *device;
|
||||
|
||||
if( SupportedVendors[vendor].vendor_id != di->pcii.vendor_id )
|
||||
continue;
|
||||
|
||||
for( device = SupportedVendors[vendor].devices; device->device_id; ++device ) {
|
||||
// avoid double-detection
|
||||
if (device->device_id != di->pcii.device_id )
|
||||
continue;
|
||||
|
||||
di->has_crtc2 = has_crtc2[device->asic];
|
||||
di->asic = device->asic;
|
||||
|
||||
if( Radeon_MapBIOS( &di->pcii, &di->rom ) != B_OK )
|
||||
// give up checking this device - no BIOS, no fun
|
||||
return false;
|
||||
|
||||
if( Radeon_ReadBIOSData( di ) != B_OK ) {
|
||||
Radeon_UnmapBIOS( &di->rom );
|
||||
return false;
|
||||
}
|
||||
|
||||
// we don't need BIOS any more
|
||||
Radeon_UnmapBIOS( &di->rom );
|
||||
|
||||
SHOW_INFO( 0, "found %s; ASIC: %s", device->name, asic_name[device->asic] );
|
||||
|
||||
sprintf(di->name, "graphics/%04X_%04X_%02X%02X%02X",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
SHOW_FLOW( 3, "making /dev/%s", di->name );
|
||||
|
||||
di->is_open = 0;
|
||||
di->shared_area = -1;
|
||||
di->si = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// gather list of supported devices
|
||||
// (currently, we rely on proper BIOS detection, which
|
||||
// only works for primary graphics adapter, so multiple
|
||||
// devices won't really work)
|
||||
void Radeon_ProbeDevices( void )
|
||||
{
|
||||
uint32 pci_index = 0;
|
||||
uint32 count = 0;
|
||||
device_info *di = devices->di;
|
||||
|
||||
while( count < MAX_DEVICES ) {
|
||||
memset( di, 0, sizeof( *di ));
|
||||
|
||||
if( (*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) != B_NO_ERROR)
|
||||
break;
|
||||
|
||||
if( probeDevice( di )) {
|
||||
devices->device_names[count] = di->name;
|
||||
di++;
|
||||
count++;
|
||||
}
|
||||
|
||||
pci_index++;
|
||||
}
|
||||
|
||||
devices->count = count;
|
||||
devices->device_names[count] = NULL;
|
||||
|
||||
SHOW_INFO( 0, "%ld supported devices", count );
|
||||
}
|
328
src/add-ons/kernel/drivers/graphics/radeon/dma.c
Normal file
328
src/add-ons/kernel/drivers/graphics/radeon/dma.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
DMA initialization/clean-up.
|
||||
|
||||
Currently, we use PCI DMA. Changing to AGP would
|
||||
only affect this file, but AGP-GART is specific to
|
||||
the chipset of the motherboard, and as DMA is really
|
||||
overkill for 2D, I cannot bother writing a dozen
|
||||
of AGP drivers just to gain little extra speedup.
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_driver.h"
|
||||
#include <malloc.h>
|
||||
#include <image.h>
|
||||
#include <mmio.h>
|
||||
#include <buscntrl_regs.h>
|
||||
#include <memcntrl_regs.h>
|
||||
#include <cp_regs.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if 0
|
||||
// create actual DMA buffer
|
||||
static status_t createDMABuffer( DMA_buffer *buffer, size_t size )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
buffer->size = size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||
|
||||
// if this buffer is used for PCI BM, cache snooping
|
||||
// takes care of syncing memory accesses; if used for AGP,
|
||||
// we'll have to access via AGP aperture (and mark aperture
|
||||
// as write-combined) as cache consistency doesn't need to
|
||||
// be guaranteed
|
||||
|
||||
// the specs say that some chipsets do kind of lazy flushing
|
||||
// so the graphics card may read obsolete data; up to now
|
||||
// we use PCI only where this shouldn't happen by design;
|
||||
// if we change to AGP we may tweak the pre-charge time of
|
||||
// the write buffer pointer
|
||||
|
||||
// as some variables in accelerant point directly into
|
||||
// the DMA buffer, we have to grant access for all apps
|
||||
buffer->buffer_area = create_area( "Radeon DMA buffer",
|
||||
&buffer->ptr, B_ANY_KERNEL_ADDRESS,
|
||||
size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA );
|
||||
if( buffer->buffer_area < 0 ) {
|
||||
SHOW_ERROR( 1, "cannot create DMA buffer (%s)",
|
||||
strerror( buffer->buffer_area ));
|
||||
return buffer->buffer_area;
|
||||
}
|
||||
|
||||
memset( buffer->ptr, 0, size );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static status_t createDMABuffer( DMA_buffer *buffer, size_t size )
|
||||
{
|
||||
physical_entry map[1];
|
||||
void *unaligned_addr, *aligned_phys;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
buffer->size = size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||
|
||||
// we allocate an contiguous area having twice the size
|
||||
// to be able to find an aligned, contiguous range within it;
|
||||
// the graphics card doesn't care, but the CPU cannot
|
||||
// make an arbitrary area WC'ed, at least elder ones
|
||||
// question: is this necessary for a PCI GART because of bus snooping?
|
||||
buffer->unaligned_area = create_area( "Radeon DMA buffer",
|
||||
&unaligned_addr, B_ANY_KERNEL_ADDRESS,
|
||||
2 * size, B_CONTIGUOUS/*B_FULL_LOCK*/, B_READ_AREA | B_WRITE_AREA );
|
||||
if( buffer->unaligned_area < 0 ) {
|
||||
SHOW_ERROR( 1, "cannot create DMA buffer (%s)",
|
||||
strerror( buffer->unaligned_area ));
|
||||
return buffer->unaligned_area;
|
||||
}
|
||||
|
||||
get_memory_map( unaligned_addr, B_PAGE_SIZE, map, 1 );
|
||||
|
||||
aligned_phys =
|
||||
(void **)(((uint32)map[0].address + size - 1) & ~(size - 1));
|
||||
|
||||
SHOW_FLOW( 3, "aligned_phys=%p", aligned_phys );
|
||||
|
||||
buffer->buffer_area = map_physical_memory( "Radeon aligned DMA buffer",
|
||||
aligned_phys,
|
||||
size, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
|
||||
B_READ_AREA | B_WRITE_AREA, &buffer->ptr );
|
||||
|
||||
if( buffer->buffer_area < 0 ) {
|
||||
SHOW_ERROR0( 3, "cannot map buffer with WC" );
|
||||
buffer->buffer_area = map_physical_memory( "Radeon aligned DMA buffer",
|
||||
aligned_phys,
|
||||
size, B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, &buffer->ptr );
|
||||
}
|
||||
|
||||
if( buffer->buffer_area < 0 ) {
|
||||
SHOW_ERROR0( 1, "cannot map DMA buffer" );
|
||||
delete_area( buffer->unaligned_area );
|
||||
buffer->unaligned_area = -1;
|
||||
return buffer->buffer_area;
|
||||
}
|
||||
|
||||
memset( buffer->ptr, 0, size );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// init GART (could be used for both PCI and AGP)
|
||||
static status_t initGART( DMA_buffer *buffer )
|
||||
{
|
||||
physical_entry *map;
|
||||
physical_entry PTB_map[1];
|
||||
size_t map_count;
|
||||
int i;
|
||||
uint32 *gart_entry;
|
||||
size_t num_pages;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
num_pages = (buffer->size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||
|
||||
// GART must be contignuous
|
||||
buffer->GART_area = create_area( "Radeon GART", (void **)&buffer->GART_ptr,
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
(num_pages * sizeof( uint32 ) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1),
|
||||
B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA );
|
||||
|
||||
if( buffer->GART_area < 0 ) {
|
||||
SHOW_ERROR( 1, "cannot create GART table (%s)",
|
||||
strerror( buffer->GART_area ));
|
||||
return buffer->GART_area;
|
||||
}
|
||||
|
||||
get_memory_map( buffer->GART_ptr, B_PAGE_SIZE, PTB_map, 1 );
|
||||
buffer->GART_phys = (uint32)PTB_map[0].address;
|
||||
|
||||
SHOW_INFO( 3, "GART_ptr=%p, GART_phys=%p", buffer->GART_ptr,
|
||||
(void *)buffer->GART_phys );
|
||||
|
||||
// get address mapping
|
||||
memset( buffer->GART_ptr, 0, num_pages * sizeof( uint32 ));
|
||||
|
||||
map_count = num_pages + 1;
|
||||
map = malloc( map_count * sizeof( physical_entry ) );
|
||||
|
||||
get_memory_map( buffer->ptr, buffer->size, map, map_count );
|
||||
|
||||
// the following looks a bit strange as the kernel
|
||||
// combines successive entries
|
||||
gart_entry = buffer->GART_ptr;
|
||||
|
||||
for( i = 0; i < (int)map_count; ++i ) {
|
||||
uint32 addr = (uint32)map[i].address;
|
||||
size_t size = map[i].size;
|
||||
|
||||
if( size == 0 )
|
||||
break;
|
||||
|
||||
while( size > 0 ) {
|
||||
*gart_entry++ = addr;
|
||||
//SHOW_FLOW( 3, "%lx", *(gart_entry-1) );
|
||||
addr += ATI_PCIGART_PAGE_SIZE;
|
||||
size -= ATI_PCIGART_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
free( map );
|
||||
|
||||
if( i == (int)map_count ) {
|
||||
// this case should never happen
|
||||
SHOW_ERROR0( 0, "memory map of DMA buffer too large!" );
|
||||
delete_area( buffer->GART_area );
|
||||
buffer->GART_area = -1;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// this might be a bit more than needed, as
|
||||
// 1. Intel CPUs have "processor order", i.e. writes appear to external
|
||||
// devices in program order, so a simple final write should be sufficient
|
||||
// 2. if it is a PCI GART, bus snooping should provide cache coherence
|
||||
// 3. this function is a no-op :(
|
||||
clear_caches( buffer->GART_ptr, num_pages * sizeof( uint32 ),
|
||||
B_FLUSH_DCACHE );
|
||||
|
||||
// back to real live - some chipsets have write buffers that
|
||||
// proove all previous assumption wrong
|
||||
asm volatile ( "wbinvd" ::: "memory" );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// destroy DMA buffer
|
||||
static void destroyDMABuffer( DMA_buffer *buffer )
|
||||
{
|
||||
if( buffer->buffer_area >= 0 )
|
||||
delete_area( buffer->buffer_area );
|
||||
|
||||
buffer->buffer_area = -1;
|
||||
}
|
||||
|
||||
|
||||
// destroy GART
|
||||
static void destroyGART( DMA_buffer *buffer )
|
||||
{
|
||||
if( buffer->unaligned_area >= 0 )
|
||||
delete_area( buffer->unaligned_area );
|
||||
|
||||
if( buffer->GART_area >= 0 )
|
||||
delete_area( buffer->GART_area );
|
||||
|
||||
buffer->GART_area = -1;
|
||||
}
|
||||
|
||||
|
||||
// initialize DMA (well - we initialize entire memory controller)
|
||||
status_t Radeon_InitDMA( device_info *di )
|
||||
{
|
||||
vuint8 *regs = di->regs;
|
||||
shared_info *si = di->si;
|
||||
status_t result;
|
||||
|
||||
// any address not covered by frame buffer, PCI GART or AGP aperture
|
||||
// leads to a direct memory access
|
||||
// -> this is dangerous, so we make sure entire address space is mapped
|
||||
|
||||
// locate PCI GART at top of address space
|
||||
si->nonlocal_vm_start = -ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
|
||||
si->nonlocal_mem_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
|
||||
|
||||
SHOW_INFO( 3, "Non-local memory %lx@%lx (graphics card address)",
|
||||
si->nonlocal_mem_size, si->nonlocal_vm_start );
|
||||
|
||||
// let AGP range overlap with frame buffer to hide it;
|
||||
// according to spec, frame buffer should win but we better
|
||||
// choose an unused-area to avoid trouble
|
||||
// (specs don't talk about overlapping area, let's hope
|
||||
// the memory controller won't choke if we ever access it)
|
||||
si->AGP_vm_start = si->nonlocal_vm_start - 0x10000;
|
||||
si->AGP_vm_size = 0x10000;
|
||||
|
||||
result = createDMABuffer( &di->DMABuffer, 0x80000 );
|
||||
if( result < 0 )
|
||||
goto err1;
|
||||
|
||||
result = initGART( &di->DMABuffer );
|
||||
if( result < 0 )
|
||||
goto err2;
|
||||
|
||||
SHOW_INFO( 3, "GART=%p", di->DMABuffer.ptr );
|
||||
|
||||
si->nonlocal_mem = di->DMABuffer.ptr;
|
||||
|
||||
// set PCI GART page-table base address
|
||||
OUTREG( regs, RADEON_AIC_PT_BASE, di->DMABuffer.GART_phys );
|
||||
|
||||
// set address range for PCI address translate
|
||||
OUTREG( regs, RADEON_AIC_LO_ADDR, si->nonlocal_vm_start );
|
||||
OUTREG( regs, RADEON_AIC_HI_ADDR, si->nonlocal_vm_start +
|
||||
di->DMABuffer.size - 1 );
|
||||
|
||||
// set AGP address range
|
||||
OUTREG( regs, RADEON_MC_AGP_LOCATION,
|
||||
(si->AGP_vm_start & 0xffff0000) |
|
||||
((si->AGP_vm_start + si->AGP_vm_size - 1) >> 16 ));
|
||||
|
||||
// set address range of video memory
|
||||
// (lower word = begin >> 16
|
||||
// upper word = end >> 16)
|
||||
// let it cover all remaining addresses;
|
||||
// addresses are wrapped
|
||||
OUTREG( regs, RADEON_MC_FB_LOCATION,
|
||||
((si->nonlocal_vm_start - 1) & 0xffff0000) |
|
||||
(0 >> 16) );
|
||||
|
||||
// disable AGP
|
||||
OUTREG( regs, RADEON_AGP_COMMAND, 0 );
|
||||
|
||||
// Turn on PCI GART
|
||||
#if 1
|
||||
OUTREGP( regs, RADEON_AIC_CNTL, RADEON_PCIGART_TRANSLATE_EN,
|
||||
~RADEON_PCIGART_TRANSLATE_EN );
|
||||
#endif
|
||||
|
||||
// SHOW_FLOW0( 3, "done" );
|
||||
|
||||
return B_OK;
|
||||
|
||||
err2:
|
||||
destroyDMABuffer( &di->DMABuffer );
|
||||
|
||||
err1:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// cleanup DMA
|
||||
void Radeon_CleanupDMA( device_info *di )
|
||||
{
|
||||
vuint8 *regs = di->regs;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// perhaps we should wait for FIFO space before messing around with registers, but
|
||||
// 1. I don't want to add all the sync stuff to the kernel driver
|
||||
// 2. I doubt that these regs are buffered by FIFO
|
||||
|
||||
// disable CP BM
|
||||
OUTREG( regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
|
||||
// disable bus mastering
|
||||
OUTREGP( regs, RADEON_BUS_CNTL, RADEON_BUS_MASTER_DIS, ~RADEON_BUS_MASTER_DIS );
|
||||
// disable PCI GART
|
||||
OUTREGP( regs, RADEON_AIC_CNTL, 0, ~RADEON_PCIGART_TRANSLATE_EN );
|
||||
|
||||
destroyGART( &di->DMABuffer );
|
||||
destroyDMABuffer( &di->DMABuffer );
|
||||
}
|
275
src/add-ons/kernel/drivers/graphics/radeon/driver.c
Normal file
275
src/add-ons/kernel/drivers/graphics/radeon/driver.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
DevFS interface
|
||||
*/
|
||||
|
||||
#include "radeon_driver.h"
|
||||
#ifdef ENABLE_LOGGING
|
||||
#include "log_coll.h"
|
||||
#endif
|
||||
|
||||
#include <OS.h>
|
||||
#include <malloc.h>
|
||||
#include <graphic_driver.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mmio.h>
|
||||
#include <version.h>
|
||||
|
||||
// tell the kernel what revision of the driver API we support
|
||||
//int32 api_version = 2;
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION; // apsed, was 2, is 2 in R5
|
||||
|
||||
|
||||
static status_t open_hook( const char *name, uint32 flags, void **cookie );
|
||||
static status_t close_hook( void *dev );
|
||||
static status_t free_hook( void *dev );
|
||||
static status_t read_hook( void *dev, off_t pos, void *buf, size_t *len );
|
||||
static status_t write_hook( void *dev, off_t pos, const void *buf, size_t *len );
|
||||
static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len );
|
||||
|
||||
|
||||
static device_hooks graphics_device_hooks = {
|
||||
open_hook,
|
||||
close_hook,
|
||||
free_hook,
|
||||
control_hook,
|
||||
read_hook,
|
||||
write_hook,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
// public function: check whether there is *any* supported hardware
|
||||
status_t init_hardware( void )
|
||||
{
|
||||
SHOW_INFO0( 0, RADEON_DRIVER_VERSION );
|
||||
if( Radeon_CardDetect() == B_OK )
|
||||
return B_OK;
|
||||
else
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// public function: init driver
|
||||
status_t init_driver( void )
|
||||
{
|
||||
if( get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK )
|
||||
return B_ERROR;
|
||||
|
||||
/* driver private data */
|
||||
devices = (radeon_devices *)calloc( 1, sizeof( radeon_devices ));
|
||||
if( devices == NULL ) {
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
INIT_BEN( "Radeon Kernel", devices->kernel);
|
||||
|
||||
Radeon_ProbeDevices();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// public function: uninit driver
|
||||
void uninit_driver( void )
|
||||
{
|
||||
DELETE_BEN( devices->kernel );
|
||||
|
||||
free( devices );
|
||||
devices = NULL;
|
||||
|
||||
put_module( B_PCI_MODULE_NAME );
|
||||
}
|
||||
|
||||
|
||||
// public function: return list of device names
|
||||
const char **publish_devices( void )
|
||||
{
|
||||
return (const char **)devices->device_names;
|
||||
}
|
||||
|
||||
|
||||
// public function: find hooks for specific device given its name
|
||||
device_hooks *find_device( const char *name )
|
||||
{
|
||||
uint32 index;
|
||||
|
||||
// probably, we could always return standard hooks
|
||||
for( index = 0; devices->device_names[index]; ++index ) {
|
||||
if( strcmp( name, devices->device_names[index] ) == 0 )
|
||||
return &graphics_device_hooks;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// public function: open device
|
||||
static status_t open_hook( const char *name, uint32 flags, void **cookie )
|
||||
{
|
||||
int32 index = 0;
|
||||
device_info *di;
|
||||
status_t result = B_OK;
|
||||
|
||||
SHOW_FLOW( 3, "name=%s, flags=%ld, cookie=0x%08lx", name, flags, (uint32)cookie );
|
||||
|
||||
// find device info
|
||||
while( devices->device_names[index] &&
|
||||
strcmp(name, devices->device_names[index] ) != 0 )
|
||||
index++;
|
||||
|
||||
di = &(devices->di[index]);
|
||||
|
||||
ACQUIRE_BEN( devices->kernel );
|
||||
|
||||
if( !di->is_open )
|
||||
result = Radeon_FirstOpen( di );
|
||||
|
||||
if( result == B_OK ) {
|
||||
di->is_open++;
|
||||
*cookie = di;
|
||||
}
|
||||
|
||||
RELEASE_BEN( devices->kernel );
|
||||
|
||||
SHOW_FLOW( 3, "returning 0x%08lx", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// public function: read from device (denied)
|
||||
static status_t read_hook( void *dev, off_t pos, void *buf, size_t *len )
|
||||
{
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
// public function: write to device (denied)
|
||||
static status_t write_hook( void *dev, off_t pos, const void *buf, size_t *len )
|
||||
{
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
// public function: close device (ignored, wait for free_hook instead)
|
||||
static status_t close_hook( void *dev )
|
||||
{
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// public function: free device
|
||||
static status_t free_hook( void *dev )
|
||||
{
|
||||
device_info *di = (device_info *)dev;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
ACQUIRE_BEN( devices->kernel );
|
||||
|
||||
mem_freetag( di->local_memmgr, dev );
|
||||
|
||||
if( di->is_open == 1 )
|
||||
Radeon_LastClose( di );
|
||||
|
||||
di->is_open--;
|
||||
RELEASE_BEN( devices->kernel );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// public function: ioctl
|
||||
static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
|
||||
{
|
||||
device_info *di = (device_info *)dev;
|
||||
status_t result = B_DEV_INVALID_IOCTL;
|
||||
|
||||
switch (msg) {
|
||||
// needed by app_server to load accelerant
|
||||
case B_GET_ACCELERANT_SIGNATURE: {
|
||||
char *sig = (char *)buf;
|
||||
//strcpy(sig, "radeon2.accelerant");
|
||||
strcpy(sig, "radeon.accelerant");
|
||||
result = B_OK;
|
||||
} break;
|
||||
|
||||
// needed to share data between kernel and accelerant
|
||||
case RADEON_GET_PRIVATE_DATA: {
|
||||
radeon_get_private_data *gpd = (radeon_get_private_data *)buf;
|
||||
|
||||
if (gpd->magic == RADEON_PRIVATE_DATA_MAGIC) {
|
||||
gpd->shared_info_area = di->shared_area;
|
||||
gpd->virtual_card_area = di->virtual_card_area;
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
|
||||
// needed for cloning
|
||||
case RADEON_DEVICE_NAME: {
|
||||
radeon_device_name *dn = (radeon_device_name *)buf;
|
||||
|
||||
if( dn->magic == RADEON_PRIVATE_DATA_MAGIC ) {
|
||||
strncpy( dn->name, di->name, MAX_RADEON_DEVICE_NAME_LENGTH );
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
|
||||
// graphics mem manager
|
||||
case RADEON_ALLOC_LOCAL_MEM: {
|
||||
radeon_alloc_local_mem *am = (radeon_alloc_local_mem *)buf;
|
||||
|
||||
if( am->magic == RADEON_PRIVATE_DATA_MAGIC )
|
||||
result = mem_alloc( di->local_memmgr, am->size, dev, &am->handle, &am->fb_offset );
|
||||
} break;
|
||||
|
||||
case RADEON_FREE_LOCAL_MEM: {
|
||||
radeon_free_local_mem *fm = (radeon_free_local_mem *)buf;
|
||||
|
||||
if( fm->magic == RADEON_PRIVATE_DATA_MAGIC )
|
||||
result = mem_free( di->local_memmgr, fm->handle, dev );
|
||||
} break;
|
||||
|
||||
// interface to log data
|
||||
#ifdef ENABLE_LOGGING
|
||||
case RADEON_GET_LOG_SIZE:
|
||||
*(uint32 *)buf = log_getsize( di->si->log );
|
||||
result = B_OK;
|
||||
break;
|
||||
|
||||
case RADEON_GET_LOG_DATA:
|
||||
log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
|
||||
result = B_OK;
|
||||
break;
|
||||
#endif
|
||||
|
||||
// interface to i2c-bus
|
||||
case RADEON_SET_I2C_SIGNALS: {
|
||||
radeon_getset_i2c *data = (radeon_getset_i2c *)buf;
|
||||
|
||||
if( data->magic == RADEON_PRIVATE_DATA_MAGIC ) {
|
||||
result = B_OK;
|
||||
OUTREG( di->regs, data->port, data->value );
|
||||
}
|
||||
break; }
|
||||
case RADEON_GET_I2C_SIGNALS: {
|
||||
radeon_getset_i2c *data = (radeon_getset_i2c *)buf;
|
||||
|
||||
if( data->magic == RADEON_PRIVATE_DATA_MAGIC ) {
|
||||
result = B_OK;
|
||||
data->value = INREG( di->regs, data->port );
|
||||
}
|
||||
break; }
|
||||
}
|
||||
return result;
|
||||
}
|
18
src/add-ons/kernel/drivers/graphics/radeon/global_data.c
Normal file
18
src/add-ons/kernel/drivers/graphics/radeon/global_data.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Global variables
|
||||
*/
|
||||
|
||||
#include "radeon_driver.h"
|
||||
|
||||
|
||||
int debug_level_flow = 4;
|
||||
int debug_level_info = 4;
|
||||
int debug_level_error = 4;
|
||||
|
||||
radeon_devices *devices;
|
||||
pci_module_info *pci_bus;
|
312
src/add-ons/kernel/drivers/graphics/radeon/init.c
Normal file
312
src/add-ons/kernel/drivers/graphics/radeon/init.c
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Init and clean-up of devices
|
||||
|
||||
TBD: support for multiple virtual card per device is
|
||||
not implemented yet - there is only one per device;
|
||||
apart from additional device names, we need proper
|
||||
management of graphics mem to not interfere.
|
||||
*/
|
||||
|
||||
#include "radeon_driver.h"
|
||||
|
||||
#include <PCI.h>
|
||||
#include <stdio.h>
|
||||
#include <dac_regs.h>
|
||||
#include <mmio.h>
|
||||
|
||||
// helper macros for easier PCI access
|
||||
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
|
||||
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
|
||||
|
||||
|
||||
// map frame buffer and registers
|
||||
// mmio_only - true = map registers only (used during detection)
|
||||
status_t Radeon_MapDevice( device_info *di, bool mmio_only )
|
||||
{
|
||||
// framebuffer is stored in PCI range 0,
|
||||
// register map in PCI range 2
|
||||
int regs = 2;
|
||||
int fb = 0;
|
||||
char buffer[B_OS_NAME_LENGTH];
|
||||
shared_info *si = di->si;
|
||||
uint32 tmp;
|
||||
pci_info *pcii = &(di->pcii);
|
||||
status_t result;
|
||||
|
||||
SHOW_FLOW( 3, "device: %02X%02X%02X",
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function );
|
||||
|
||||
si->regs_area = si->fb_area = 0;
|
||||
|
||||
// enable memory mapped IO and frame buffer
|
||||
// also, enable bus mastering (some BIOSes seem to
|
||||
// disable that, like mine)
|
||||
tmp = get_pci( PCI_command, 2 );
|
||||
SHOW_FLOW( 3, "old PCI command state: 0x%08lx", tmp );
|
||||
tmp |= PCI_command_io | PCI_command_memory | PCI_command_master;
|
||||
set_pci( PCI_command, 2, tmp );
|
||||
|
||||
// registers cannot be accessed directly by user apps,
|
||||
// they need to clone area for safety reasons
|
||||
SHOW_INFO( 1, "physical address of memory-mapped I/O: 0x%8lx-0x%8lx",
|
||||
di->pcii.u.h0.base_registers[regs],
|
||||
di->pcii.u.h0.base_registers[regs] + di->pcii.u.h0.base_register_sizes[regs] - 1 );
|
||||
|
||||
sprintf( buffer, "%04X_%04X_%02X%02X%02X regs",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function );
|
||||
|
||||
si->regs_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[regs],
|
||||
di->pcii.u.h0.base_register_sizes[regs],
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
0,
|
||||
(void **)&(di->regs));
|
||||
if( si->regs_area < 0 )
|
||||
return si->regs_area;
|
||||
|
||||
if( mmio_only )
|
||||
return B_OK;
|
||||
|
||||
if( di->pcii.u.h0.base_register_sizes[fb] > di->local_mem_size ) {
|
||||
// Radeons allocate more address range then really needed ->
|
||||
// only map the area that contains physical memory
|
||||
SHOW_INFO( 1, "restrict frame buffer from 0x%8lx to 0x%8lx bytes",
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
di->local_mem_size
|
||||
);
|
||||
di->pcii.u.h0.base_register_sizes[fb] = di->local_mem_size;
|
||||
}
|
||||
|
||||
// framebuffer can be accessed by everyone
|
||||
// this is not a perfect solution; preferably, only
|
||||
// those areas owned by an application are mapped into
|
||||
// its address space
|
||||
SHOW_INFO( 1, "physical address of framebuffer: 0x%8lx-0x%8lx",
|
||||
di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_registers[fb] + di->pcii.u.h0.base_register_sizes[fb] - 1 );
|
||||
|
||||
sprintf(buffer, "%04X_%04X_%02X%02X%02X framebuffer",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
|
||||
si->fb_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
(void **)&(si->framebuffer));
|
||||
|
||||
if (si->fb_area < 0) {
|
||||
SHOW_FLOW0( 3, "couldn't enable WC for frame buffer" );
|
||||
si->fb_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
(void **)&(si->framebuffer));
|
||||
}
|
||||
|
||||
SHOW_FLOW( 3, "mapped frame buffer @%p", si->framebuffer );
|
||||
|
||||
if (si->fb_area < 0) {
|
||||
result = si->fb_area;
|
||||
goto err;
|
||||
}
|
||||
|
||||
// save physical address though noone can probably make
|
||||
// any use of it
|
||||
si->framebuffer_pci = (void *) di->pcii.u.h0.base_registers_pci[fb];
|
||||
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
delete_area(si->regs_area);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// unmap PCI ranges
|
||||
void Radeon_UnmapDevice(device_info *di)
|
||||
{
|
||||
shared_info *si = di->si;
|
||||
pci_info *pcii = &(di->pcii);
|
||||
uint32 tmp;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// disable PCI ranges (though it probably won't
|
||||
// hurt leaving them enabled)
|
||||
tmp = get_pci( PCI_command, 2 );
|
||||
tmp &= ~PCI_command_io | PCI_command_memory | PCI_command_master;
|
||||
set_pci( PCI_command, 2, tmp );
|
||||
|
||||
if( si->regs_area > 0 )
|
||||
delete_area( si->regs_area );
|
||||
|
||||
if( si->fb_area > 0 )
|
||||
delete_area( si->fb_area );
|
||||
|
||||
si->regs_area = si->fb_area = 0;
|
||||
}
|
||||
|
||||
|
||||
// initialize shared infos on first open
|
||||
status_t Radeon_FirstOpen( device_info *di )
|
||||
{
|
||||
status_t result;
|
||||
char buffer[B_OS_NAME_LENGTH];
|
||||
shared_info *si;
|
||||
//uint32 /*dma_block, */dma_offset;
|
||||
|
||||
// create shared info; don't allow access by apps -
|
||||
// they'll clone it
|
||||
sprintf( buffer, "%04X_%04X_%02X%02X%02X shared",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function );
|
||||
|
||||
di->shared_area = create_area(
|
||||
buffer,
|
||||
(void **)&(di->si),
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
(sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1),
|
||||
B_FULL_LOCK, 0);
|
||||
if (di->shared_area < 0) {
|
||||
result = di->shared_area;
|
||||
goto err8;
|
||||
}
|
||||
|
||||
memset( di->si, 0, sizeof( *di->si ));
|
||||
|
||||
si = di->si;
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
si->log = log_init( 1000000 );
|
||||
#endif
|
||||
|
||||
// copy all info into shared info
|
||||
si->vendor_id = di->pcii.vendor_id;
|
||||
si->device_id = di->pcii.device_id;
|
||||
si->revision = di->pcii.revision;
|
||||
|
||||
si->has_crtc2 = di->has_crtc2;
|
||||
si->asic = di->asic;
|
||||
|
||||
si->ports[0].disp_type = di->disp_type[0];
|
||||
si->ports[1].disp_type = di->disp_type[1];
|
||||
si->fp_port = di->fp_info;
|
||||
si->pll = di->pll;
|
||||
/* si->ram = di->ram;
|
||||
strcpy( si->ram_type, di->ram_type );*/
|
||||
si->local_mem_size = di->local_mem_size;
|
||||
|
||||
// create virtual card info; don't allow access by apps -
|
||||
// they'll clone it
|
||||
sprintf( buffer, "%04X_%04X_%02X%02X%02X virtual card 0",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function );
|
||||
di->virtual_card_area = create_area(
|
||||
buffer,
|
||||
(void **)&(di->vc),
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
(sizeof(virtual_card) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1),
|
||||
B_FULL_LOCK, 0);
|
||||
if (di->virtual_card_area < 0) {
|
||||
result = di->virtual_card_area;
|
||||
goto err5;
|
||||
}
|
||||
|
||||
// currently, we assign fixed ports to this virtual card
|
||||
di->vc->num_ports = si->has_crtc2 ? 2 : 1;
|
||||
di->vc->ports[0].is_crtc2 = false;
|
||||
di->vc->ports[0].physical_port = 0;
|
||||
di->vc->ports[1].is_crtc2 = true;
|
||||
di->vc->ports[1].physical_port = 1;
|
||||
|
||||
di->vc->fb_mem_handle = 0;
|
||||
di->vc->cursor.mem_handle = 0;
|
||||
|
||||
// create unique id
|
||||
di->vc->id = di->virtual_card_area;
|
||||
|
||||
result = Radeon_MapDevice( di, false );
|
||||
if (result < 0)
|
||||
goto err4;
|
||||
|
||||
// save dac2_cntl register
|
||||
// we need to restore that during uninit, else you only get
|
||||
// garbage on screen on reboot
|
||||
if( di->has_crtc2 )
|
||||
di->dac2_cntl = INREG( di->regs, RADEON_DAC_CNTL2 );
|
||||
|
||||
result = Radeon_InitDMA( di );
|
||||
if( result < 0 )
|
||||
goto err3;
|
||||
|
||||
// currently, we don't support VLI - something is broken there
|
||||
// (it doesn't change a thing apart from crashing)
|
||||
/* result = Radeon_SetupIRQ( di, buffer );
|
||||
if( result < 0 )
|
||||
goto err2;*/
|
||||
|
||||
di->local_memmgr = mem_init( 0, di->local_mem_size, 1024,
|
||||
di->local_mem_size / 1024 );
|
||||
if( di->local_memmgr == NULL ) {
|
||||
result = B_NO_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
//Radeon_Fix_AGP();
|
||||
|
||||
// mem_alloc( di->local_memmgr, 0x100000, (void *)-1, &dma_block, &dma_offset );
|
||||
/* dma_offset = 15 * 1024 * 1024;
|
||||
|
||||
si->nonlocal_mem = (uint32 *)((uint32)si->framebuffer + dma_offset);
|
||||
si->nonlocal_vm_start = (uint32)si->framebuffer_pci + dma_offset;*/
|
||||
|
||||
return B_OK;
|
||||
|
||||
err1:
|
||||
/*Radeon_CleanupIRQ( di );
|
||||
err2:*/
|
||||
Radeon_CleanupDMA( di );
|
||||
err3:
|
||||
Radeon_UnmapDevice( di );
|
||||
err4:
|
||||
delete_area( di->virtual_card_area );
|
||||
err5:
|
||||
delete_area( di->shared_area );
|
||||
err8:
|
||||
return result;
|
||||
}
|
||||
|
||||
// clean up shared info on last close
|
||||
// (we could for device destruction, but this makes
|
||||
// testing easier as everythings gets cleaned up
|
||||
// during tests)
|
||||
void Radeon_LastClose( device_info *di )
|
||||
{
|
||||
if( di->has_crtc2 )
|
||||
OUTREG( di->regs, RADEON_DAC_CNTL2, di->dac2_cntl );
|
||||
|
||||
mem_destroy( di->local_memmgr );
|
||||
|
||||
// Radeon_CleanupIRQ( di );
|
||||
Radeon_CleanupDMA( di );
|
||||
Radeon_UnmapDevice(di);
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
log_exit( di->si->log );
|
||||
#endif
|
||||
|
||||
delete_area( di->virtual_card_area );
|
||||
delete_area( di->shared_area );
|
||||
}
|
220
src/add-ons/kernel/drivers/graphics/radeon/irq.c
Normal file
220
src/add-ons/kernel/drivers/graphics/radeon/irq.c
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Interrupt handling. Currently, none of this is used
|
||||
as I haven't got the HW spec.
|
||||
*/
|
||||
|
||||
#include "radeon_driver.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mmio.h>
|
||||
#include <rbbm_regs.h>
|
||||
|
||||
|
||||
// disable all interrupts
|
||||
static void Radeon_DisableIRQ( device_info *di )
|
||||
{
|
||||
OUTREG( di->regs, RADEON_GEN_INT_CNTL, 0 );
|
||||
}
|
||||
|
||||
|
||||
static uint32 thread_interrupt_work( vuint8 *regs, device_info *di, uint32 int_status )
|
||||
{
|
||||
shared_info *si = di->si;
|
||||
uint32 handled = B_HANDLED_INTERRUPT;
|
||||
|
||||
if( (int_status & RADEON_CRTC_VBLANK_STAT) != 0 &&
|
||||
si->ports[0].vblank >= 0 )
|
||||
{
|
||||
int32 blocked;
|
||||
|
||||
++di->vbi_count[0];
|
||||
|
||||
if( (get_sem_count( si->ports[0].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
|
||||
//SHOW_FLOW( 3, "Signalled VBI 0 (%ldx)", -blocked );
|
||||
release_sem_etc( si->ports[0].vblank, -blocked, B_DO_NOT_RESCHEDULE );
|
||||
handled = B_INVOKE_SCHEDULER;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int_status & RADEON_CRTC2_VBLANK_STAT) != 0 &&
|
||||
si->ports[1].vblank >= 0 )
|
||||
{
|
||||
int32 blocked;
|
||||
|
||||
++di->vbi_count[1];
|
||||
|
||||
if( (get_sem_count( si->ports[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
|
||||
//SHOW_FLOW( 3, "Signalled VBI 1 (%ldx)", -blocked );
|
||||
release_sem_etc( si->ports[1].vblank, -blocked, B_DO_NOT_RESCHEDULE );
|
||||
handled = B_INVOKE_SCHEDULER;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
Radeon_Interrupt(void *data)
|
||||
{
|
||||
int32 handled = B_UNHANDLED_INTERRUPT;
|
||||
device_info *di = (device_info *)data;
|
||||
vuint8 *regs = di->regs;
|
||||
int32 int_status;
|
||||
|
||||
int_status = INREG( regs, RADEON_GEN_INT_STATUS );
|
||||
|
||||
if( int_status != 0 ) {
|
||||
++di->interrupt_count;
|
||||
|
||||
handled = thread_interrupt_work( regs, di, int_status );
|
||||
OUTREG( regs, RADEON_GEN_INT_STATUS, int_status );
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
static int32 timer_interrupt_func( timer *te )
|
||||
{
|
||||
bigtime_t now = system_time();
|
||||
/* get the pointer to the device we're handling this time */
|
||||
device_info *di = ((timer_info *)te)->di;
|
||||
shared_info *si = di->si;
|
||||
vuint8 *regs = di->regs;
|
||||
uint32 vbl_status = 0 /* read vertical blank status */;
|
||||
int32 result = B_HANDLED_INTERRUPT;
|
||||
|
||||
/* are we suppoesed to handle interrupts still? */
|
||||
if( !di->shutdown_virtual_irq ) {
|
||||
/* reschedule with same period by default */
|
||||
bigtime_t when = si->refresh_period;
|
||||
timer *to;
|
||||
|
||||
/* if interrupts are "enabled", do our thing */
|
||||
if( si->enable_virtual_irq ) {
|
||||
/* insert code to sync to interrupts here */
|
||||
if (!vbl_status) {
|
||||
when -= si->blank_period - 4;
|
||||
}
|
||||
/* do the things we do when we notice a vertical retrace */
|
||||
result = thread_interrupt_work( regs, di,
|
||||
RADEON_CRTC_VBLANK_STAT |
|
||||
(di->has_crtc2 ? RADEON_CRTC_VBLANK_STAT : 0 ));
|
||||
}
|
||||
|
||||
/* pick the "other" timer */
|
||||
to = (timer *)&(di->ti_a);
|
||||
if (to == te) to = (timer *)&(di->ti_b);
|
||||
/* our guess as to when we should be back */
|
||||
((timer_info *)to)->when_target = now + when;
|
||||
/* reschedule the interrupt */
|
||||
add_timer(to, timer_interrupt_func, ((timer_info *)to)->when_target, B_ONE_SHOT_ABSOLUTE_TIMER);
|
||||
/* remember the currently active timer */
|
||||
di->current_timer = (timer_info *)to;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t Radeon_SetupIRQ( device_info *di, char *buffer )
|
||||
{
|
||||
shared_info *si = di->si;
|
||||
status_t result;
|
||||
thread_id thid;
|
||||
thread_info thinfo;
|
||||
|
||||
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 0",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function );
|
||||
si->ports[0].vblank = create_sem( 0, buffer );
|
||||
if( si->ports[0].vblank < 0 ) {
|
||||
result = si->ports[0].vblank;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 1",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function );
|
||||
si->ports[1].vblank = create_sem( 0, buffer );
|
||||
if( si->ports[1].vblank < 0 ) {
|
||||
result = si->ports[1].vblank;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* change the owner of the semaphores to the opener's team */
|
||||
/* this is required because apps can't aquire kernel semaphores */
|
||||
thid = find_thread(NULL);
|
||||
get_thread_info(thid, &thinfo);
|
||||
set_sem_owner(si->ports[0].vblank, thinfo.team);
|
||||
set_sem_owner(si->ports[1].vblank, thinfo.team);
|
||||
|
||||
/* disable and clear any pending interrupts */
|
||||
Radeon_DisableIRQ( di );
|
||||
|
||||
/* if we're faking interrupts */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
SHOW_INFO0( 3, "We like to fake IRQ" );
|
||||
/* fake some kind of interrupt with a timer */
|
||||
di->shutdown_virtual_irq = false;
|
||||
si->refresh_period = 16666; /* fake 60Hz to start */
|
||||
si->blank_period = si->refresh_period / 20;
|
||||
|
||||
di->ti_a.di = di; /* refer to ourself */
|
||||
di->ti_b.di = di;
|
||||
di->current_timer = &(di->ti_a);
|
||||
|
||||
/* program the first timer interrupt, and it will handle the rest */
|
||||
result = add_timer((timer *)(di->current_timer), timer_interrupt_func,
|
||||
si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER);
|
||||
if( result != B_OK )
|
||||
goto err3;
|
||||
} else {
|
||||
/* otherwise install our interrupt handler */
|
||||
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line,
|
||||
Radeon_Interrupt, (void *)di, 0);
|
||||
if( result != B_OK )
|
||||
goto err3;
|
||||
|
||||
SHOW_INFO( 3, "installed IRQ @ %d", di->pcii.u.h0.interrupt_line );
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
delete_sem( si->ports[1].vblank );
|
||||
err2:
|
||||
delete_sem( si->ports[0].vblank );
|
||||
err1:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Radeon_CleanupIRQ( device_info *di )
|
||||
{
|
||||
shared_info *si = di->si;
|
||||
|
||||
Radeon_DisableIRQ( di );
|
||||
|
||||
/* if we were faking the interrupts */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
/* stop our interrupt faking thread */
|
||||
di->shutdown_virtual_irq = true;
|
||||
/* cancel the timer */
|
||||
/* we don't know which one is current, so cancel them both and ignore any error */
|
||||
cancel_timer((timer *)&(di->ti_a));
|
||||
cancel_timer((timer *)&(di->ti_b));
|
||||
} else {
|
||||
/* remove interrupt handler */
|
||||
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, Radeon_Interrupt, di);
|
||||
}
|
||||
|
||||
delete_sem( si->ports[1].vblank );
|
||||
delete_sem( si->ports[0].vblank );
|
||||
|
||||
si->ports[1].vblank = si->ports[0].vblank = 0;
|
||||
}
|
255
src/add-ons/kernel/drivers/graphics/radeon/memmgr.c
Normal file
255
src/add-ons/kernel/drivers/graphics/radeon/memmgr.c
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Memory manager used for graphics mem
|
||||
|
||||
|
||||
It has the following features
|
||||
- doesn't access memory to be managed
|
||||
- memory block's owner is identified by tag,
|
||||
tag is verified during free, and all memory
|
||||
belonging to one tag can be freed at once
|
||||
- multi-threading save
|
||||
*/
|
||||
|
||||
#include "memmgr.h"
|
||||
#include <stdlib.h>
|
||||
#include "radeon_driver.h"
|
||||
|
||||
// init manager
|
||||
// start - start of address space
|
||||
// len - len of address space
|
||||
// block_size - granularity
|
||||
// heap_entries - maximum number of blocks
|
||||
mem_info *mem_init( uint32 start, uint32 len, uint32 block_size, uint32 heap_entries )
|
||||
{
|
||||
mem_block *first;
|
||||
mem_info *mem;
|
||||
uint i;
|
||||
|
||||
SHOW_FLOW( 2, "start=%lx, len=%lx, block_size=%lx, heap_entries=%ld",
|
||||
start, len, block_size, heap_entries );
|
||||
|
||||
mem = malloc( sizeof( *mem ));
|
||||
if( mem == NULL )
|
||||
goto err;
|
||||
|
||||
mem->block_size = block_size;
|
||||
mem->heap_entries = heap_entries;
|
||||
mem->lock = create_sem( 1, "mem_lock" );
|
||||
|
||||
if( mem->lock < 0 )
|
||||
goto err2;
|
||||
|
||||
mem->heap = malloc( heap_entries * sizeof( mem_block ));
|
||||
if( mem->heap == NULL )
|
||||
goto err3;
|
||||
|
||||
for( i = 1; i < heap_entries; ++i )
|
||||
mem->heap[i].next = &mem->heap[i+1];
|
||||
|
||||
mem->heap[heap_entries - 1].next = NULL;
|
||||
mem->unused = &mem->heap[1];
|
||||
|
||||
first = &mem->heap[0];
|
||||
mem->first = first;
|
||||
|
||||
first->base = start;
|
||||
first->size = len;
|
||||
first->prev = first->next = NULL;
|
||||
first->alloced = false;
|
||||
|
||||
return mem;
|
||||
|
||||
err3:
|
||||
delete_sem( mem->lock );
|
||||
err2:
|
||||
free( mem );
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// destroy heap
|
||||
void mem_destroy( mem_info *mem )
|
||||
{
|
||||
SHOW_FLOW0( 2, "" );
|
||||
|
||||
free( mem->heap );
|
||||
delete_sem( mem->lock );
|
||||
free( mem );
|
||||
}
|
||||
|
||||
|
||||
// allocate memory block
|
||||
// in:
|
||||
// mem - heap handle
|
||||
// size - size in bytes
|
||||
// tag - owner tag
|
||||
// out:
|
||||
// block - block id
|
||||
// offset - start address of block
|
||||
status_t mem_alloc( mem_info *mem, uint32 size, void *tag, uint32 *block, uint32 *offset )
|
||||
{
|
||||
mem_block *cur, *new_entry;
|
||||
|
||||
SHOW_FLOW( 2, "size=%ld, tag=%p", size, tag );
|
||||
|
||||
acquire_sem( mem->lock );
|
||||
|
||||
// we assume block_size is power of two
|
||||
size = (size + mem->block_size - 1) & ~(mem->block_size - 1);
|
||||
|
||||
// simple first fit
|
||||
for( cur = mem->first; cur; cur = cur->next ) {
|
||||
if( !cur->alloced && cur->size >= size )
|
||||
break;
|
||||
}
|
||||
|
||||
if( cur == NULL ) {
|
||||
SHOW_FLOW0( 2, "out of memory" );
|
||||
goto err;
|
||||
}
|
||||
|
||||
if( size != cur->size ) {
|
||||
new_entry = mem->unused;
|
||||
|
||||
if( new_entry == NULL ) {
|
||||
SHOW_FLOW0( 2, "out of blocks" );
|
||||
goto err;
|
||||
}
|
||||
|
||||
mem->unused = new_entry->next;
|
||||
|
||||
new_entry->next = cur->next;
|
||||
new_entry->prev = cur;
|
||||
new_entry->alloced = false;
|
||||
new_entry->base = cur->base + size;
|
||||
new_entry->size = cur->size - size;
|
||||
|
||||
if( cur->next )
|
||||
cur->next->prev = new_entry;
|
||||
|
||||
cur->next = new_entry;
|
||||
cur->size = size;
|
||||
}
|
||||
|
||||
cur->alloced = true;
|
||||
cur->tag = tag;
|
||||
|
||||
*block = cur - mem->heap + 1;
|
||||
*offset = cur->base;
|
||||
|
||||
release_sem( mem->lock );
|
||||
|
||||
SHOW_FLOW( 2, "block_id=%ld, offset=%lx", *block, *offset );
|
||||
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
release_sem( mem->lock );
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
// merge "block" with successor
|
||||
static void merge( mem_info *mem, mem_block *block )
|
||||
{
|
||||
mem_block *next;
|
||||
|
||||
next = block->next;
|
||||
|
||||
block->size += next->size;
|
||||
|
||||
if( next->next )
|
||||
next->next->prev = block;
|
||||
|
||||
block->next = next->next;
|
||||
|
||||
next->next = mem->unused;
|
||||
mem->unused = next;
|
||||
}
|
||||
|
||||
|
||||
// internal: free memory block including merge
|
||||
static mem_block *freeblock( mem_info *mem, mem_block *block )
|
||||
{
|
||||
mem_block *prev, *next;
|
||||
|
||||
block->alloced = false;
|
||||
|
||||
prev = block->prev;
|
||||
|
||||
if( prev && !prev->alloced ) {
|
||||
block = prev;
|
||||
merge( mem, prev );
|
||||
}
|
||||
|
||||
next = block->next;
|
||||
|
||||
if( next && !next->alloced )
|
||||
merge( mem, block );
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
// free memory
|
||||
// mem - heap handle
|
||||
// block_id - block id
|
||||
// tag - owner tag (must match tag passed to mem_alloc)
|
||||
status_t mem_free( mem_info *mem, uint32 block_id, void *tag )
|
||||
{
|
||||
mem_block *block;
|
||||
|
||||
SHOW_FLOW( 2, "block_id=%ld, tag=%p", block_id, tag );
|
||||
|
||||
acquire_sem( mem->lock );
|
||||
|
||||
--block_id;
|
||||
|
||||
if( block_id >= mem->heap_entries ) {
|
||||
SHOW_FLOW0( 2, "invalid id" );
|
||||
goto err;
|
||||
}
|
||||
|
||||
block = &mem->heap[block_id];
|
||||
if( !block->alloced || block->tag != tag ) {
|
||||
SHOW_FLOW0( 2, "not owner" );
|
||||
goto err;
|
||||
}
|
||||
|
||||
freeblock( mem, block );
|
||||
|
||||
release_sem( mem->lock );
|
||||
|
||||
SHOW_FLOW0( 2, "success" );
|
||||
return B_OK;
|
||||
|
||||
err:
|
||||
release_sem( mem->lock );
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
// free all memory belonging to owner "tag"
|
||||
void mem_freetag( mem_info *mem, void *tag )
|
||||
{
|
||||
mem_block *cur;
|
||||
|
||||
SHOW_FLOW( 2, "tag=%p", tag );
|
||||
|
||||
acquire_sem( mem->lock );
|
||||
|
||||
for( cur = mem->first; cur; cur = cur->next ) {
|
||||
if( cur->alloced && cur->tag == tag )
|
||||
cur = freeblock( mem, cur );
|
||||
}
|
||||
|
||||
release_sem( mem->lock );
|
||||
|
||||
SHOW_FLOW0( 2, "done" );
|
||||
}
|
43
src/add-ons/kernel/drivers/graphics/radeon/memmgr.h
Normal file
43
src/add-ons/kernel/drivers/graphics/radeon/memmgr.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Memory manager used for graphics mem
|
||||
*/
|
||||
|
||||
#ifndef _MEMMGR_H
|
||||
#define _MEMMGR_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
// allocated memory block
|
||||
typedef struct mem_block {
|
||||
struct mem_block *prev, *next;
|
||||
uint32 base;
|
||||
uint32 size;
|
||||
void *tag;
|
||||
bool alloced;
|
||||
} mem_block;
|
||||
|
||||
|
||||
// memory heap
|
||||
typedef struct mem_info {
|
||||
mem_block *first;
|
||||
uint32 block_size;
|
||||
sem_id lock;
|
||||
mem_block *heap;
|
||||
mem_block *unused;
|
||||
uint32 heap_entries;
|
||||
} mem_info;
|
||||
|
||||
|
||||
mem_info *mem_init( uint32 start, uint32 len, uint32 block_size, uint32 heap_entries );
|
||||
void mem_destroy( mem_info *mem );
|
||||
status_t mem_alloc( mem_info *mem, uint32 size, void *tag, uint32 *block, uint32 *offset );
|
||||
status_t mem_free( mem_info *mem, uint32 block_id, void *tag );
|
||||
void mem_freetag( mem_info *mem, void *tag );
|
||||
|
||||
#endif
|
166
src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h
Normal file
166
src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon kernel driver
|
||||
|
||||
Common header file
|
||||
*/
|
||||
|
||||
#ifndef _RADEON_DRIVER_H
|
||||
#define _RADEON_DRIVER_H
|
||||
|
||||
#include <radeon_interface.h>
|
||||
#include "memmgr.h"
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
|
||||
// logging helpers
|
||||
extern int debug_level_flow;
|
||||
extern int debug_level_info;
|
||||
extern int debug_level_error;
|
||||
|
||||
/*#define DEBUG_WAIT_ON_MSG 1000000
|
||||
#define DEBUG_WAIT_ON_ERROR 1000000*/
|
||||
|
||||
#define DEBUG_MSG_PREFIX "Radeon - "
|
||||
#include <debug_ext.h>
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
#include "log_coll.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
|
||||
// DMA buffer
|
||||
typedef struct DMA_buffer {
|
||||
area_id buffer_area;
|
||||
size_t size;
|
||||
void *ptr;
|
||||
|
||||
area_id GART_area;
|
||||
uint32 *GART_ptr;
|
||||
uint32 GART_phys;
|
||||
area_id unaligned_area;
|
||||
} DMA_buffer;
|
||||
|
||||
// info about graphics RAM
|
||||
typedef struct {
|
||||
int ml;
|
||||
int MB;
|
||||
int Trcd;
|
||||
int Trp;
|
||||
int Twr;
|
||||
int CL;
|
||||
int Tr2w;
|
||||
int loop_latency;
|
||||
int Rloop;
|
||||
} ram_info;
|
||||
|
||||
typedef struct {
|
||||
area_id bios_area;
|
||||
|
||||
uint8 *bios_ptr; // begin of entire BIOS
|
||||
uint8 *rom_ptr; // begin of ROM containing hw info
|
||||
} rom_info;
|
||||
|
||||
|
||||
// timer for VBI emulation
|
||||
typedef struct {
|
||||
timer te; /* timer entry for add_timer() */
|
||||
struct device_info *di; /* pointer to the owning device */
|
||||
bigtime_t when_target; /* when we're supposed to wake up */
|
||||
} timer_info;
|
||||
|
||||
|
||||
// info about one device
|
||||
typedef struct device_info {
|
||||
uint32 is_open;
|
||||
area_id shared_area;
|
||||
shared_info *si;
|
||||
|
||||
area_id virtual_card_area;
|
||||
virtual_card *vc;
|
||||
vuint8 *regs;
|
||||
|
||||
bool has_crtc2;
|
||||
radeon_type asic;
|
||||
display_type_e disp_type[2];
|
||||
fp_info fp_info;
|
||||
|
||||
pll_info pll;
|
||||
ram_info ram;
|
||||
char ram_type[32]; // human-readable name of ram type
|
||||
uint32 local_mem_size;
|
||||
|
||||
rom_info rom;
|
||||
|
||||
DMA_buffer DMABuffer;
|
||||
|
||||
mem_info *local_memmgr;
|
||||
|
||||
// VBI data
|
||||
uint32 interrupt_count;
|
||||
uint32 vbi_count[2];
|
||||
// VBI emulation
|
||||
int32 shutdown_virtual_irq; // true, to shutdown virtual interrupts
|
||||
timer_info ti_a; /* a pool of two timer managment buffers */
|
||||
timer_info ti_b;
|
||||
timer_info *current_timer; /* the timer buffer that's currently in use */
|
||||
|
||||
uint32 dac2_cntl; // original dac2_cntl register content
|
||||
|
||||
pci_info pcii;
|
||||
char name[MAX_RADEON_DEVICE_NAME_LENGTH];
|
||||
} device_info;
|
||||
|
||||
|
||||
// device list and some global data
|
||||
typedef struct {
|
||||
uint32 count;
|
||||
benaphore kernel;
|
||||
char *device_names[MAX_DEVICES+1];
|
||||
device_info di[MAX_DEVICES];
|
||||
} radeon_devices;
|
||||
|
||||
|
||||
extern pci_module_info *pci_bus;
|
||||
extern radeon_devices *devices;
|
||||
|
||||
|
||||
// detect.c
|
||||
bool Radeon_CardDetect( void );
|
||||
void Radeon_ProbeDevices( void );
|
||||
|
||||
|
||||
// init.c
|
||||
status_t Radeon_FirstOpen( device_info *di );
|
||||
void Radeon_LastClose( device_info *di );
|
||||
status_t Radeon_MapDevice( device_info *di, bool mmio_only );
|
||||
void Radeon_UnmapDevice(device_info *di);
|
||||
|
||||
|
||||
// bios.c
|
||||
status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri );
|
||||
void Radeon_UnmapBIOS( rom_info *ri );
|
||||
status_t Radeon_ReadBIOSData( device_info *di );
|
||||
|
||||
|
||||
// dma.c
|
||||
void Radeon_CleanupDMA( device_info *di );
|
||||
status_t Radeon_InitDMA( device_info *di );
|
||||
|
||||
|
||||
// irq.c
|
||||
status_t Radeon_SetupIRQ( device_info *di, char *buffer );
|
||||
void Radeon_CleanupIRQ( device_info *di );
|
||||
|
||||
|
||||
// agp.c
|
||||
void Radeon_Fix_AGP();
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user