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:
shadow303 2004-03-15 00:57:31 +00:00
parent bbd8e7fbd9
commit 1da2dde8c2
12 changed files with 2814 additions and 0 deletions

View 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 ;
}

View 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 );
}
}
}

View 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;
}

View 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 );
}

View 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 );
}

View 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;
}

View 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;

View 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 );
}

View 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;
}

View 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" );
}

View 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

View 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