Convert Thomas's radeon driver to out build structure.
Still needs work in order to properly enable logging and extra settings. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6985 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Public functions to provide 2D hardware acceleration
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "cp_regs.h"
|
||||
#include "3d_regs.h"
|
||||
#include "2d_regs.h"
|
||||
#include "mmio.h"
|
||||
|
||||
|
||||
// currently, an CP instruction stream is written to
|
||||
// a buffer on stack and then copied into the official
|
||||
// CP buffer
|
||||
|
||||
#define PACKET_BUFFER_LEN 0x100
|
||||
|
||||
// copy screen to screen
|
||||
// et - ignored
|
||||
// list - list of rectangles
|
||||
// count - number of rectangles
|
||||
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
int offset = 0;
|
||||
uint32 buffer[PACKET_BUFFER_LEN];
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
for( ; count > 0; --count, ++list ) {
|
||||
if( offset == 0 ) {
|
||||
buffer[offset++] = RADEON_CP_PACKET3_CNTL_BITBLT_MULTI;
|
||||
buffer[offset++] = RADEON_GMC_BRUSH_NONE
|
||||
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
|
||||
| RADEON_GMC_SRC_DATATYPE_COLOR
|
||||
| RADEON_ROP3_S
|
||||
| RADEON_DP_SRC_SOURCE_MEMORY;
|
||||
}
|
||||
|
||||
buffer[offset++] = (list->src_left << 16) | list->src_top;
|
||||
buffer[offset++] = (list->dest_left << 16) | list->dest_top;
|
||||
buffer[offset++] = ((list->width + 1) << 16) | (list->height + 1);
|
||||
|
||||
if( offset + 3 > PACKET_BUFFER_LEN ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( offset > 0 ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
}
|
||||
|
||||
++ai->si->engine.count;
|
||||
}
|
||||
|
||||
|
||||
// fill rectangles on screen
|
||||
// et - ignored
|
||||
// colorIndex - fill colour
|
||||
// list - list of rectangles
|
||||
// count - number of rectangles
|
||||
void FILL_RECTANGLE(engine_token *et, uint32 colorIndex,
|
||||
fill_rect_params *list, uint32 count)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
int offset = 0;
|
||||
uint32 buffer[PACKET_BUFFER_LEN];
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
for( ; count > 0; --count, ++list ) {
|
||||
if( offset == 0 ) {
|
||||
buffer[offset++] = RADEON_CP_PACKET3_CNTL_PAINT_MULTI;
|
||||
buffer[offset++] = RADEON_GMC_BRUSH_SOLID_COLOR
|
||||
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
|
||||
| RADEON_GMC_SRC_DATATYPE_COLOR
|
||||
| RADEON_ROP3_P;
|
||||
buffer[offset++] = colorIndex;
|
||||
}
|
||||
|
||||
buffer[offset++] = (list->left << 16) | list->top;
|
||||
buffer[offset++] =
|
||||
((list->right - list->left + 1) << 16) |
|
||||
(list->bottom - list->top + 1);
|
||||
|
||||
if( offset + 2 > PACKET_BUFFER_LEN ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( offset > 0 ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
}
|
||||
|
||||
++ai->si->engine.count;
|
||||
}
|
||||
|
||||
|
||||
// invert rectangle on screen
|
||||
// et - ignored
|
||||
// list - list of rectangles
|
||||
// count - number of rectangles
|
||||
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
int offset = 0;
|
||||
uint32 buffer[PACKET_BUFFER_LEN];
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
for( ; count > 0; --count, ++list ) {
|
||||
if( offset == 0 ) {
|
||||
buffer[offset++] = RADEON_CP_PACKET3_CNTL_PAINT_MULTI;
|
||||
buffer[offset++] = RADEON_GMC_BRUSH_NONE
|
||||
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
|
||||
| RADEON_GMC_SRC_DATATYPE_COLOR
|
||||
| RADEON_ROP3_Dn;
|
||||
}
|
||||
|
||||
buffer[offset++] = (list->left << 16) | list->top;
|
||||
buffer[offset++] =
|
||||
((list->right - list->left + 1) << 16) |
|
||||
(list->bottom - list->top + 1);
|
||||
|
||||
// always leave 2 extra bytes for fix (see below)
|
||||
if( offset + 2 > PACKET_BUFFER_LEN - 2 ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
// we have to reset ROP, else we get garbage during next
|
||||
// CPU access; it looks like some cache coherency/forwarding
|
||||
// problem as it goes away later on; things like flushing the
|
||||
// destination cache or waiting for 2D engine or HDP to become
|
||||
// idle and clean didn't change a thing
|
||||
// (I dont't really understand what exactly happens,
|
||||
// but this code fixes it)
|
||||
buffer[offset++] = CP_PACKET0( RADEON_DP_GUI_MASTER_CNTL, 0 );
|
||||
buffer[offset++] = RADEON_GMC_BRUSH_NONE
|
||||
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
|
||||
| RADEON_GMC_SRC_DATATYPE_COLOR
|
||||
| RADEON_ROP3_S
|
||||
| RADEON_DP_SRC_SOURCE_MEMORY;
|
||||
|
||||
if( offset > 0 )
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
|
||||
++ai->si->engine.count;
|
||||
}
|
||||
|
||||
// fill horizontal spans on screen
|
||||
// et - ignored
|
||||
// colorIndex - fill colour
|
||||
// list - list of spans
|
||||
// count - number of spans
|
||||
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
int offset = 0;
|
||||
uint32 buffer[PACKET_BUFFER_LEN];
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
for( ; count > 0; --count ) {
|
||||
uint16 y, x, width;
|
||||
|
||||
if( offset == 0 ) {
|
||||
buffer[offset++] = RADEON_CP_PACKET3_CNTL_PAINT_MULTI;
|
||||
buffer[offset++] = RADEON_GMC_BRUSH_SOLID_COLOR
|
||||
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
|
||||
| RADEON_GMC_SRC_DATATYPE_COLOR
|
||||
| RADEON_ROP3_P;
|
||||
buffer[offset++] = colorIndex;
|
||||
}
|
||||
|
||||
y = *list++;
|
||||
x = *list++;
|
||||
width = *list++ - x + 1;
|
||||
|
||||
buffer[offset++] = (x << 16) | y;
|
||||
buffer[offset++] = (width << 16) | 1;
|
||||
|
||||
if( offset + 2 > PACKET_BUFFER_LEN ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( offset > 0 ) {
|
||||
buffer[0] |= (offset - 2) << 16;
|
||||
|
||||
Radeon_SendCP( ai, buffer, offset );
|
||||
}
|
||||
|
||||
++ai->si->engine.count;
|
||||
}
|
||||
|
||||
|
||||
// prepare 2D acceleration
|
||||
void Radeon_Init2D( accelerator_info *ai, uint32 datatype )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// forget about 3D
|
||||
OUTREG( ai->regs, RADEON_RB3D_CNTL, 0 );
|
||||
|
||||
//Radeon_ResetEngine( ai );
|
||||
|
||||
// no siccors
|
||||
Radeon_WaitForFifo( ai, 1 );
|
||||
OUTREG( ai->regs, RADEON_DEFAULT_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX
|
||||
| RADEON_DEFAULT_SC_BOTTOM_MAX));
|
||||
|
||||
// setup general flags - perhaps this is not needed as all
|
||||
// 2D commands contain this register
|
||||
Radeon_WaitForFifo( ai, 1 );
|
||||
OUTREG( ai->regs, RADEON_DP_GUI_MASTER_CNTL,
|
||||
(datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
|
||||
| RADEON_GMC_CLR_CMP_CNTL_DIS
|
||||
|
||||
| RADEON_GMC_BRUSH_SOLID_COLOR
|
||||
| RADEON_GMC_SRC_DATATYPE_COLOR
|
||||
|
||||
| RADEON_ROP3_P
|
||||
| RADEON_DP_SRC_SOURCE_MEMORY
|
||||
| RADEON_GMC_WR_MSK_DIS );
|
||||
|
||||
|
||||
// most of this init is probably not nessacary
|
||||
// as we neither draw lines nor use brushes
|
||||
Radeon_WaitForFifo( ai, 7 );
|
||||
OUTREG( ai->regs, RADEON_DST_LINE_START, 0);
|
||||
OUTREG( ai->regs, RADEON_DST_LINE_END, 0);
|
||||
OUTREG( ai->regs, RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff);
|
||||
OUTREG( ai->regs, RADEON_DP_BRUSH_BKGD_CLR, 0x00000000);
|
||||
OUTREG( ai->regs, RADEON_DP_SRC_FRGD_CLR, 0xffffffff);
|
||||
OUTREG( ai->regs, RADEON_DP_SRC_BKGD_CLR, 0x00000000);
|
||||
OUTREG( ai->regs, RADEON_DP_WRITE_MASK, 0xffffffff);
|
||||
|
||||
Radeon_WaitForIdle( ai );
|
||||
}
|
||||
|
||||
// switch to virtual card, i.e. setup all specific engine registers
|
||||
void Radeon_ActivateVirtualCard( accelerator_info *ai )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
uint32 buffer[3*2];
|
||||
uint32 pitch_offset;
|
||||
int idx = 0;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
pitch_offset = (vc->fb_offset >> 10) | ((vc->pitch >> 6) << 22);
|
||||
buffer[idx++] = CP_PACKET0( RADEON_DEFAULT_OFFSET, 0 );
|
||||
buffer[idx++] = pitch_offset;
|
||||
buffer[idx++] = CP_PACKET0( RADEON_DST_PITCH_OFFSET, 0 );
|
||||
buffer[idx++] = pitch_offset;
|
||||
buffer[idx++] = CP_PACKET0( RADEON_SRC_PITCH_OFFSET, 0 );
|
||||
buffer[idx++] = pitch_offset;
|
||||
|
||||
Radeon_SendCP( ai, buffer, idx );
|
||||
|
||||
ai->si->active_vc = vc->id;
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Command Processor handling
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "mmio.h"
|
||||
#include "CPMicroCode.h"
|
||||
#include "cp_regs.h"
|
||||
#include "buscntrl_regs.h"
|
||||
#include "utils.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "log_coll.h"
|
||||
#include "log_enum.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
uint getAvailRingBuffer( accelerator_info *ai );
|
||||
|
||||
|
||||
// non-local memory is used as following:
|
||||
// - 0x10000 dwords for ring buffer
|
||||
// - 8 dwords for returned data (i.e. current read ptr)
|
||||
// - 6 dwords for "scratch registers"
|
||||
//
|
||||
// usage of scratch registers:
|
||||
// - reg 0 = reached engine.count
|
||||
//
|
||||
// the ring buffer stuff must be at a constant offset as
|
||||
// clones cannot be informed if it were changed
|
||||
|
||||
|
||||
// upload Micro-Code of CP
|
||||
static void loadMicroEngineRAMData( accelerator_info *ai )
|
||||
{
|
||||
int i;
|
||||
const uint32 (*microcode)[2];
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
switch( ai->si->asic ) {
|
||||
case rt_r300:
|
||||
case rt_r300_4p:
|
||||
case rt_rv350:
|
||||
case rt_rv360:
|
||||
case rt_r350:
|
||||
case rt_r360:
|
||||
microcode = r300_cp_microcode;
|
||||
break;
|
||||
case rt_r200:
|
||||
//case rt_rv250:
|
||||
//case rt_m9:
|
||||
microcode = r200_cp_microcode;
|
||||
break;
|
||||
default:
|
||||
microcode = radeon_cp_microcode;
|
||||
}
|
||||
|
||||
Radeon_WaitForIdle( ai );
|
||||
|
||||
OUTREG( ai->regs, RADEON_CP_ME_RAM_ADDR, 0 );
|
||||
|
||||
for ( i = 0 ; i < 256 ; i++ ) {
|
||||
OUTREG( ai->regs, RADEON_CP_ME_RAM_DATAH, microcode[i][1] );
|
||||
OUTREG( ai->regs, RADEON_CP_ME_RAM_DATAL, microcode[i][0] );
|
||||
}
|
||||
}
|
||||
|
||||
// convert CPU's to graphics card's virtual address
|
||||
#define CPU2GC( addr ) (((uint32)(addr) - (uint32)si->nonlocal_mem) + si->nonlocal_vm_start)
|
||||
|
||||
// initialize bus mastering
|
||||
static status_t setupCPRegisters( accelerator_info *ai, int aring_size )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
shared_info *si = ai->si;
|
||||
uint32 tmp;
|
||||
|
||||
#if 0
|
||||
{
|
||||
// allocate ring buffer etc. from local memory instead of PCI memory
|
||||
radeon_alloc_local_mem am;
|
||||
|
||||
am.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
am.size = (aring_size + 14) * 4;
|
||||
|
||||
if( ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am ) != B_OK )
|
||||
SHOW_ERROR0( 0, "Cannot allocate ring buffer from local memory" );
|
||||
else {
|
||||
si->nonlocal_vm_start = am.fb_offset;
|
||||
si->nonlocal_mem = (uint32 *)(si->framebuffer + am.fb_offset);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
memset( &si->ring, 0, sizeof( si->ring ));
|
||||
|
||||
// set write pointer delay to zero;
|
||||
// we assume that memory synchronization is done correctly my MoBo
|
||||
// and Radeon_SendCP contains a hack that hopefully fixes such problems
|
||||
OUTREG( regs, RADEON_CP_RB_WPTR_DELAY, 0 );
|
||||
|
||||
// setup CP buffer
|
||||
si->ring.start = si->nonlocal_mem;
|
||||
si->ring.size = aring_size;
|
||||
OUTREG( regs, RADEON_CP_RB_BASE, CPU2GC( si->ring.start ));
|
||||
SHOW_INFO( 3, "CP buffer address=%lx", CPU2GC( si->ring.start ));
|
||||
|
||||
// setup CP read pointer buffer
|
||||
si->ring.head = si->ring.start + si->ring.size;
|
||||
OUTREG( regs, RADEON_CP_RB_RPTR_ADDR, CPU2GC( si->ring.head ));
|
||||
SHOW_INFO( 3, "CP read pointer buffer==%lx", CPU2GC( si->ring.head ));
|
||||
|
||||
// set ring buffer size
|
||||
// (it's log2 of qwords)
|
||||
OUTREG( regs, RADEON_CP_RB_CNTL, log2( si->ring.size / 2 ));
|
||||
SHOW_INFO( 3, "CP buffer size mask=%ld", log2( si->ring.size / 2 ) );
|
||||
|
||||
// set CP buffer pointers
|
||||
OUTREG( regs, RADEON_CP_RB_RPTR, 0 );
|
||||
OUTREG( regs, RADEON_CP_RB_WPTR, 0 );
|
||||
*si->ring.head = 0;
|
||||
si->ring.tail = 0;
|
||||
|
||||
// setup scratch register buffer
|
||||
si->scratch_ptr = si->ring.head + RADEON_SCRATCH_REG_OFFSET / sizeof( uint32 );
|
||||
OUTREG( regs, RADEON_SCRATCH_ADDR, CPU2GC( si->scratch_ptr ));
|
||||
OUTREG( regs, RADEON_SCRATCH_UMSK, 0x3f );
|
||||
|
||||
Radeon_WaitForIdle( ai );
|
||||
|
||||
// enable bus mastering
|
||||
#if 1
|
||||
tmp = INREG( ai->regs, RADEON_BUS_CNTL ) & ~RADEON_BUS_MASTER_DIS;
|
||||
OUTREG( regs, RADEON_BUS_CNTL, tmp );
|
||||
#endif
|
||||
|
||||
// sync units
|
||||
OUTREG( regs, RADEON_ISYNC_CNTL,
|
||||
(RADEON_ISYNC_ANY2D_IDLE3D |
|
||||
RADEON_ISYNC_ANY3D_IDLE2D |
|
||||
RADEON_ISYNC_WAIT_IDLEGUI |
|
||||
RADEON_ISYNC_CPSCRATCH_IDLEGUI) );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// get number of free entries in CP's ring buffer
|
||||
uint getAvailRingBuffer( accelerator_info *ai )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
int space;
|
||||
|
||||
// space = *si->ring.head - si->ring.tail;
|
||||
space = INREG( ai->regs, RADEON_CP_RB_RPTR ) - si->ring.tail;
|
||||
|
||||
if( space <= 0 )
|
||||
space += si->ring.size;
|
||||
|
||||
// don't fill up the entire buffer as we cannot
|
||||
// distinguish between a full and an empty ring
|
||||
--space;
|
||||
|
||||
SHOW_FLOW( 4, "head=%ld, tail=%ld, space=%ld", *si->ring.head, si->ring.tail, space );
|
||||
|
||||
LOG1( si->log, _GetAvailRingBufferQueue, space );
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
// initialize CP so it's ready for BM
|
||||
status_t Radeon_InitCP( accelerator_info *ai )
|
||||
{
|
||||
// shared_info *si = ai->si;
|
||||
status_t result;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// init raw CP
|
||||
loadMicroEngineRAMData( ai );
|
||||
|
||||
// do soft-reset
|
||||
Radeon_ResetEngine( ai );
|
||||
|
||||
// after warm-reset, the CP may still be active and thus react to
|
||||
// register writes during initialization unpredictably, so we better
|
||||
// stop it first
|
||||
OUTREG( ai->regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
|
||||
INREG( ai->regs, RADEON_CP_CSQ_CNTL );
|
||||
|
||||
// reset CP to make disabling active
|
||||
Radeon_ResetEngine( ai );
|
||||
|
||||
// setup CP memory ranges
|
||||
result = setupCPRegisters( ai, 0x10000 );
|
||||
if( result < 0 )
|
||||
return result;
|
||||
|
||||
// tell CP to use BM
|
||||
Radeon_WaitForIdle( ai );
|
||||
OUTREG( ai->regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM );
|
||||
|
||||
// this may be a bit too much
|
||||
Radeon_SendPurgeCache( ai );
|
||||
Radeon_SendWaitUntilIdle( ai );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// write to register via CP
|
||||
void Radeon_WriteRegCP( accelerator_info *ai, uint32 reg, uint32 value )
|
||||
{
|
||||
uint32 buffer[2];
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
LOG2( ai->si->log, _Radeon_WriteRegFifo, reg, value );
|
||||
|
||||
buffer[0] = CP_PACKET0( reg, 0 );
|
||||
buffer[1] = value;
|
||||
|
||||
Radeon_SendCP( ai, buffer, 2 );
|
||||
}
|
||||
|
||||
|
||||
// send packets to CP
|
||||
void Radeon_SendCP( accelerator_info *ai, uint32 *buffer, uint32 num_dwords )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
|
||||
SHOW_FLOW( 4, "num_dwords=%d", num_dwords );
|
||||
|
||||
while( num_dwords > 0 ) {
|
||||
uint32 space;
|
||||
uint32 max_copy;
|
||||
// uint i;
|
||||
|
||||
space = getAvailRingBuffer( ai );
|
||||
|
||||
if( space == 0 )
|
||||
continue;
|
||||
|
||||
max_copy = min( space, num_dwords );
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
for( i = 0; i < max_copy; ++i )
|
||||
LOG1( si->log, _Radeon_SendCP, buffer[i] );
|
||||
#endif
|
||||
|
||||
if( si->ring.tail + max_copy >= si->ring.size ) {
|
||||
uint32 sub_len;
|
||||
|
||||
sub_len = si->ring.size - si->ring.tail;
|
||||
memcpy( si->ring.start + si->ring.tail, buffer, sub_len * sizeof( uint32 ));
|
||||
buffer += sub_len;
|
||||
num_dwords -= sub_len;
|
||||
max_copy -= sub_len;
|
||||
si->ring.tail = 0;
|
||||
}
|
||||
|
||||
memcpy( si->ring.start + si->ring.tail, buffer, max_copy * sizeof( uint32 ) );
|
||||
buffer += max_copy;
|
||||
num_dwords -= max_copy;
|
||||
if( si->ring.tail + max_copy < si->ring.size )
|
||||
si->ring.tail += max_copy;
|
||||
else
|
||||
si->ring.tail = 0;
|
||||
}
|
||||
|
||||
// some chipsets have problems with write buffers; effectively, the command
|
||||
// list we've just created gets delayed in some queue and the graphics chip
|
||||
// reads out-dated commands, which don't make sense and thus crash the
|
||||
// graphics card
|
||||
|
||||
// flush writes to ring
|
||||
// (this code is a bit of a overkill - currently, only some WinChip/Cyrix
|
||||
// CPU's support out-of-order writes, but we are prepared)
|
||||
__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
|
||||
// make sure the chipset has flushed its write buffer by
|
||||
// reading some uncached memory
|
||||
(void)*si->ring.head;
|
||||
|
||||
// now, the command list should really be written to memory,
|
||||
// so it's safe to instruct the graphics card to read it
|
||||
OUTREG( ai->regs, RADEON_CP_RB_WPTR, si->ring.tail );
|
||||
|
||||
// read from PCI bus to ensure correct posting
|
||||
INREG( ai->regs, RADEON_CP_RB_RPTR );
|
||||
}
|
||||
@@ -0,0 +1,786 @@
|
||||
#ifndef _CPMICROCODE_H
|
||||
#define _CPMICROCODE_H
|
||||
|
||||
// CP microcode (from ATI)
|
||||
// if you take a look at the hex-dump
|
||||
// you find some hidden message ;)
|
||||
static const uint32 radeon_cp_microcode[][2] = {
|
||||
{ 0x21007000, 0000000000 },
|
||||
{ 0x20007000, 0000000000 },
|
||||
{ 0x000000b4, 0x00000004 },
|
||||
{ 0x000000b8, 0x00000004 },
|
||||
{ 0x6f5b4d4c, 0000000000 },
|
||||
{ 0x4c4c427f, 0000000000 },
|
||||
{ 0x5b568a92, 0000000000 },
|
||||
{ 0x4ca09c6d, 0000000000 },
|
||||
{ 0xad4c4c4c, 0000000000 },
|
||||
{ 0x4ce1af3d, 0000000000 },
|
||||
{ 0xd8afafaf, 0000000000 },
|
||||
{ 0xd64c4cdc, 0000000000 },
|
||||
{ 0x4cd10d10, 0000000000 },
|
||||
{ 0x000f0000, 0x00000016 },
|
||||
{ 0x362f242d, 0000000000 },
|
||||
{ 0x00000012, 0x00000004 },
|
||||
{ 0x000f0000, 0x00000016 },
|
||||
{ 0x362f282d, 0000000000 },
|
||||
{ 0x000380e7, 0x00000002 },
|
||||
{ 0x04002c97, 0x00000002 },
|
||||
{ 0x000f0001, 0x00000016 },
|
||||
{ 0x333a3730, 0000000000 },
|
||||
{ 0x000077ef, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000021, 0x0000001a },
|
||||
{ 0x00004000, 0x0000001e },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000021, 0x0000001a },
|
||||
{ 0x00004000, 0x0000001e },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000021, 0x0000001a },
|
||||
{ 0x00004000, 0x0000001e },
|
||||
{ 0x00000017, 0x00000004 },
|
||||
{ 0x0003802b, 0x00000002 },
|
||||
{ 0x040067e0, 0x00000002 },
|
||||
{ 0x00000017, 0x00000004 },
|
||||
{ 0x000077e0, 0x00000002 },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x000037e1, 0x00000002 },
|
||||
{ 0x040067e1, 0x00000006 },
|
||||
{ 0x000077e0, 0x00000002 },
|
||||
{ 0x000077e1, 0x00000002 },
|
||||
{ 0x000077e1, 0x00000006 },
|
||||
{ 0xffffffff, 0000000000 },
|
||||
{ 0x10000000, 0000000000 },
|
||||
{ 0x0003802b, 0x00000002 },
|
||||
{ 0x040067e0, 0x00000006 },
|
||||
{ 0x00007675, 0x00000002 },
|
||||
{ 0x00007676, 0x00000002 },
|
||||
{ 0x00007677, 0x00000002 },
|
||||
{ 0x00007678, 0x00000006 },
|
||||
{ 0x0003802c, 0x00000002 },
|
||||
{ 0x04002676, 0x00000002 },
|
||||
{ 0x00007677, 0x00000002 },
|
||||
{ 0x00007678, 0x00000006 },
|
||||
{ 0x0000002f, 0x00000018 },
|
||||
{ 0x0000002f, 0x00000018 },
|
||||
{ 0000000000, 0x00000006 },
|
||||
{ 0x00000030, 0x00000018 },
|
||||
{ 0x00000030, 0x00000018 },
|
||||
{ 0000000000, 0x00000006 },
|
||||
{ 0x01605000, 0x00000002 },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x00098000, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x64c0603e, 0x00000004 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00080000, 0x00000016 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0x0400251d, 0x00000002 },
|
||||
{ 0x00007580, 0x00000002 },
|
||||
{ 0x00067581, 0x00000002 },
|
||||
{ 0x04002580, 0x00000002 },
|
||||
{ 0x00067581, 0x00000002 },
|
||||
{ 0x00000049, 0x00000004 },
|
||||
{ 0x00005000, 0000000000 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x0000750e, 0x00000002 },
|
||||
{ 0x00019000, 0x00000002 },
|
||||
{ 0x00011055, 0x00000014 },
|
||||
{ 0x00000055, 0x00000012 },
|
||||
{ 0x0400250f, 0x00000002 },
|
||||
{ 0x0000504f, 0x00000004 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00007565, 0x00000002 },
|
||||
{ 0x00007566, 0x00000002 },
|
||||
{ 0x00000058, 0x00000004 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x01e655b4, 0x00000002 },
|
||||
{ 0x4401b0e4, 0x00000002 },
|
||||
{ 0x01c110e4, 0x00000002 },
|
||||
{ 0x26667066, 0x00000018 },
|
||||
{ 0x040c2565, 0x00000002 },
|
||||
{ 0x00000066, 0x00000018 },
|
||||
{ 0x04002564, 0x00000002 },
|
||||
{ 0x00007566, 0x00000002 },
|
||||
{ 0x0000005d, 0x00000004 },
|
||||
{ 0x00401069, 0x00000008 },
|
||||
{ 0x00101000, 0x00000002 },
|
||||
{ 0x000d80ff, 0x00000002 },
|
||||
{ 0x0080006c, 0x00000008 },
|
||||
{ 0x000f9000, 0x00000002 },
|
||||
{ 0x000e00ff, 0x00000002 },
|
||||
{ 0000000000, 0x00000006 },
|
||||
{ 0x0000008f, 0x00000018 },
|
||||
{ 0x0000005b, 0x00000004 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00007576, 0x00000002 },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x00009000, 0x00000002 },
|
||||
{ 0x00041000, 0x00000002 },
|
||||
{ 0x0c00350e, 0x00000002 },
|
||||
{ 0x00049000, 0x00000002 },
|
||||
{ 0x00051000, 0x00000002 },
|
||||
{ 0x01e785f8, 0x00000002 },
|
||||
{ 0x00200000, 0x00000002 },
|
||||
{ 0x0060007e, 0x0000000c },
|
||||
{ 0x00007563, 0x00000002 },
|
||||
{ 0x006075f0, 0x00000021 },
|
||||
{ 0x20007073, 0x00000004 },
|
||||
{ 0x00005073, 0x00000004 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00007576, 0x00000002 },
|
||||
{ 0x00007577, 0x00000002 },
|
||||
{ 0x0000750e, 0x00000002 },
|
||||
{ 0x0000750f, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00600083, 0x0000000c },
|
||||
{ 0x006075f0, 0x00000021 },
|
||||
{ 0x000075f8, 0x00000002 },
|
||||
{ 0x00000083, 0x00000004 },
|
||||
{ 0x000a750e, 0x00000002 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x0020750f, 0x00000002 },
|
||||
{ 0x00600086, 0x00000004 },
|
||||
{ 0x00007570, 0x00000002 },
|
||||
{ 0x00007571, 0x00000002 },
|
||||
{ 0x00007572, 0x00000006 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00005000, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00007568, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000095, 0x0000000c },
|
||||
{ 0x00058000, 0x00000002 },
|
||||
{ 0x0c607562, 0x00000002 },
|
||||
{ 0x00000097, 0x00000004 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x00600096, 0x00000004 },
|
||||
{ 0x400070e5, 0000000000 },
|
||||
{ 0x000380e6, 0x00000002 },
|
||||
{ 0x040025c5, 0x00000002 },
|
||||
{ 0x000380e5, 0x00000002 },
|
||||
{ 0x000000a8, 0x0000001c },
|
||||
{ 0x000650aa, 0x00000018 },
|
||||
{ 0x040025bb, 0x00000002 },
|
||||
{ 0x000610ab, 0x00000018 },
|
||||
{ 0x040075bc, 0000000000 },
|
||||
{ 0x000075bb, 0x00000002 },
|
||||
{ 0x000075bc, 0000000000 },
|
||||
{ 0x00090000, 0x00000006 },
|
||||
{ 0x00090000, 0x00000002 },
|
||||
{ 0x000d8002, 0x00000006 },
|
||||
{ 0x00007832, 0x00000002 },
|
||||
{ 0x00005000, 0x00000002 },
|
||||
{ 0x000380e7, 0x00000002 },
|
||||
{ 0x04002c97, 0x00000002 },
|
||||
{ 0x00007820, 0x00000002 },
|
||||
{ 0x00007821, 0x00000002 },
|
||||
{ 0x00007800, 0000000000 },
|
||||
{ 0x01200000, 0x00000002 },
|
||||
{ 0x20077000, 0x00000002 },
|
||||
{ 0x01200000, 0x00000002 },
|
||||
{ 0x20007000, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x0120751b, 0x00000002 },
|
||||
{ 0x8040750a, 0x00000002 },
|
||||
{ 0x8040750b, 0x00000002 },
|
||||
{ 0x00110000, 0x00000002 },
|
||||
{ 0x000380e5, 0x00000002 },
|
||||
{ 0x000000c6, 0x0000001c },
|
||||
{ 0x000610ab, 0x00000018 },
|
||||
{ 0x844075bd, 0x00000002 },
|
||||
{ 0x000610aa, 0x00000018 },
|
||||
{ 0x840075bb, 0x00000002 },
|
||||
{ 0x000610ab, 0x00000018 },
|
||||
{ 0x844075bc, 0x00000002 },
|
||||
{ 0x000000c9, 0x00000004 },
|
||||
{ 0x804075bd, 0x00000002 },
|
||||
{ 0x800075bb, 0x00000002 },
|
||||
{ 0x804075bc, 0x00000002 },
|
||||
{ 0x00108000, 0x00000002 },
|
||||
{ 0x01400000, 0x00000002 },
|
||||
{ 0x006000cd, 0x0000000c },
|
||||
{ 0x20c07000, 0x00000020 },
|
||||
{ 0x000000cf, 0x00000012 },
|
||||
{ 0x00800000, 0x00000006 },
|
||||
{ 0x0080751d, 0x00000006 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0x0000775c, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00661000, 0x00000002 },
|
||||
{ 0x0460275d, 0x00000020 },
|
||||
{ 0x00004000, 0000000000 },
|
||||
{ 0x01e00830, 0x00000002 },
|
||||
{ 0x21007000, 0000000000 },
|
||||
{ 0x6464614d, 0000000000 },
|
||||
{ 0x69687420, 0000000000 },
|
||||
{ 0x00000073, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0x00005000, 0x00000002 },
|
||||
{ 0x000380d0, 0x00000002 },
|
||||
{ 0x040025e0, 0x00000002 },
|
||||
{ 0x000075e1, 0000000000 },
|
||||
{ 0x00000001, 0000000000 },
|
||||
{ 0x000380e0, 0x00000002 },
|
||||
{ 0x04002394, 0x00000002 },
|
||||
{ 0x00005000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0x00000008, 0000000000 },
|
||||
{ 0x00000004, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
};
|
||||
|
||||
// special r200 microcode
|
||||
static const uint32 r200_cp_microcode[][2] = {
|
||||
{ 0x21007000, 0000000000 },
|
||||
{ 0x20007000, 0000000000 },
|
||||
{ 0x000000ab, 0x00000004 },
|
||||
{ 0x000000af, 0x00000004 },
|
||||
{ 0x66544a49, 0000000000 },
|
||||
{ 0x49494174, 0000000000 },
|
||||
{ 0x54517d83, 0000000000 },
|
||||
{ 0x498d8b64, 0000000000 },
|
||||
{ 0x49494949, 0000000000 },
|
||||
{ 0x49da493c, 0000000000 },
|
||||
{ 0x49989898, 0000000000 },
|
||||
{ 0xd34949d5, 0000000000 },
|
||||
{ 0x9dc90e11, 0000000000 },
|
||||
{ 0xce9b9b9b, 0000000000 },
|
||||
{ 0x000f0000, 0x00000016 },
|
||||
{ 0x352e232c, 0000000000 },
|
||||
{ 0x00000013, 0x00000004 },
|
||||
{ 0x000f0000, 0x00000016 },
|
||||
{ 0x352e272c, 0000000000 },
|
||||
{ 0x000f0001, 0x00000016 },
|
||||
{ 0x3239362f, 0000000000 },
|
||||
{ 0x000077ef, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000020, 0x0000001a },
|
||||
{ 0x00004000, 0x0000001e },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000020, 0x0000001a },
|
||||
{ 0x00004000, 0x0000001e },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000020, 0x0000001a },
|
||||
{ 0x00004000, 0x0000001e },
|
||||
{ 0x00000016, 0x00000004 },
|
||||
{ 0x0003802a, 0x00000002 },
|
||||
{ 0x040067e0, 0x00000002 },
|
||||
{ 0x00000016, 0x00000004 },
|
||||
{ 0x000077e0, 0x00000002 },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x000037e1, 0x00000002 },
|
||||
{ 0x040067e1, 0x00000006 },
|
||||
{ 0x000077e0, 0x00000002 },
|
||||
{ 0x000077e1, 0x00000002 },
|
||||
{ 0x000077e1, 0x00000006 },
|
||||
{ 0xffffffff, 0000000000 },
|
||||
{ 0x10000000, 0000000000 },
|
||||
{ 0x0003802a, 0x00000002 },
|
||||
{ 0x040067e0, 0x00000006 },
|
||||
{ 0x00007675, 0x00000002 },
|
||||
{ 0x00007676, 0x00000002 },
|
||||
{ 0x00007677, 0x00000002 },
|
||||
{ 0x00007678, 0x00000006 },
|
||||
{ 0x0003802b, 0x00000002 },
|
||||
{ 0x04002676, 0x00000002 },
|
||||
{ 0x00007677, 0x00000002 },
|
||||
{ 0x00007678, 0x00000006 },
|
||||
{ 0x0000002e, 0x00000018 },
|
||||
{ 0x0000002e, 0x00000018 },
|
||||
{ 0000000000, 0x00000006 },
|
||||
{ 0x0000002f, 0x00000018 },
|
||||
{ 0x0000002f, 0x00000018 },
|
||||
{ 0000000000, 0x00000006 },
|
||||
{ 0x01605000, 0x00000002 },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x00098000, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x64c0603d, 0x00000004 },
|
||||
{ 0x00080000, 0x00000016 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0x0400251d, 0x00000002 },
|
||||
{ 0x00007580, 0x00000002 },
|
||||
{ 0x00067581, 0x00000002 },
|
||||
{ 0x04002580, 0x00000002 },
|
||||
{ 0x00067581, 0x00000002 },
|
||||
{ 0x00000046, 0x00000004 },
|
||||
{ 0x00005000, 0000000000 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x0000750e, 0x00000002 },
|
||||
{ 0x00019000, 0x00000002 },
|
||||
{ 0x00011055, 0x00000014 },
|
||||
{ 0x00000055, 0x00000012 },
|
||||
{ 0x0400250f, 0x00000002 },
|
||||
{ 0x0000504a, 0x00000004 },
|
||||
{ 0x00007565, 0x00000002 },
|
||||
{ 0x00007566, 0x00000002 },
|
||||
{ 0x00000051, 0x00000004 },
|
||||
{ 0x01e655b4, 0x00000002 },
|
||||
{ 0x4401b0dc, 0x00000002 },
|
||||
{ 0x01c110dc, 0x00000002 },
|
||||
{ 0x2666705d, 0x00000018 },
|
||||
{ 0x040c2565, 0x00000002 },
|
||||
{ 0x0000005d, 0x00000018 },
|
||||
{ 0x04002564, 0x00000002 },
|
||||
{ 0x00007566, 0x00000002 },
|
||||
{ 0x00000054, 0x00000004 },
|
||||
{ 0x00401060, 0x00000008 },
|
||||
{ 0x00101000, 0x00000002 },
|
||||
{ 0x000d80ff, 0x00000002 },
|
||||
{ 0x00800063, 0x00000008 },
|
||||
{ 0x000f9000, 0x00000002 },
|
||||
{ 0x000e00ff, 0x00000002 },
|
||||
{ 0000000000, 0x00000006 },
|
||||
{ 0x00000080, 0x00000018 },
|
||||
{ 0x00000054, 0x00000004 },
|
||||
{ 0x00007576, 0x00000002 },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x00009000, 0x00000002 },
|
||||
{ 0x00041000, 0x00000002 },
|
||||
{ 0x0c00350e, 0x00000002 },
|
||||
{ 0x00049000, 0x00000002 },
|
||||
{ 0x00051000, 0x00000002 },
|
||||
{ 0x01e785f8, 0x00000002 },
|
||||
{ 0x00200000, 0x00000002 },
|
||||
{ 0x00600073, 0x0000000c },
|
||||
{ 0x00007563, 0x00000002 },
|
||||
{ 0x006075f0, 0x00000021 },
|
||||
{ 0x20007068, 0x00000004 },
|
||||
{ 0x00005068, 0x00000004 },
|
||||
{ 0x00007576, 0x00000002 },
|
||||
{ 0x00007577, 0x00000002 },
|
||||
{ 0x0000750e, 0x00000002 },
|
||||
{ 0x0000750f, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00600076, 0x0000000c },
|
||||
{ 0x006075f0, 0x00000021 },
|
||||
{ 0x000075f8, 0x00000002 },
|
||||
{ 0x00000076, 0x00000004 },
|
||||
{ 0x000a750e, 0x00000002 },
|
||||
{ 0x0020750f, 0x00000002 },
|
||||
{ 0x00600079, 0x00000004 },
|
||||
{ 0x00007570, 0x00000002 },
|
||||
{ 0x00007571, 0x00000002 },
|
||||
{ 0x00007572, 0x00000006 },
|
||||
{ 0x00005000, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00007568, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x00000084, 0x0000000c },
|
||||
{ 0x00058000, 0x00000002 },
|
||||
{ 0x0c607562, 0x00000002 },
|
||||
{ 0x00000086, 0x00000004 },
|
||||
{ 0x00600085, 0x00000004 },
|
||||
{ 0x400070dd, 0000000000 },
|
||||
{ 0x000380dd, 0x00000002 },
|
||||
{ 0x00000093, 0x0000001c },
|
||||
{ 0x00065095, 0x00000018 },
|
||||
{ 0x040025bb, 0x00000002 },
|
||||
{ 0x00061096, 0x00000018 },
|
||||
{ 0x040075bc, 0000000000 },
|
||||
{ 0x000075bb, 0x00000002 },
|
||||
{ 0x000075bc, 0000000000 },
|
||||
{ 0x00090000, 0x00000006 },
|
||||
{ 0x00090000, 0x00000002 },
|
||||
{ 0x000d8002, 0x00000006 },
|
||||
{ 0x00005000, 0x00000002 },
|
||||
{ 0x00007821, 0x00000002 },
|
||||
{ 0x00007800, 0000000000 },
|
||||
{ 0x00007821, 0x00000002 },
|
||||
{ 0x00007800, 0000000000 },
|
||||
{ 0x01665000, 0x00000002 },
|
||||
{ 0x000a0000, 0x00000002 },
|
||||
{ 0x000671cc, 0x00000002 },
|
||||
{ 0x0286f1cd, 0x00000002 },
|
||||
{ 0x000000a3, 0x00000010 },
|
||||
{ 0x21007000, 0000000000 },
|
||||
{ 0x000000aa, 0x0000001c },
|
||||
{ 0x00065000, 0x00000002 },
|
||||
{ 0x000a0000, 0x00000002 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x000b0000, 0x00000002 },
|
||||
{ 0x38067000, 0x00000002 },
|
||||
{ 0x000a00a6, 0x00000004 },
|
||||
{ 0x20007000, 0000000000 },
|
||||
{ 0x01200000, 0x00000002 },
|
||||
{ 0x20077000, 0x00000002 },
|
||||
{ 0x01200000, 0x00000002 },
|
||||
{ 0x20007000, 0000000000 },
|
||||
{ 0x00061000, 0x00000002 },
|
||||
{ 0x0120751b, 0x00000002 },
|
||||
{ 0x8040750a, 0x00000002 },
|
||||
{ 0x8040750b, 0x00000002 },
|
||||
{ 0x00110000, 0x00000002 },
|
||||
{ 0x000380dd, 0x00000002 },
|
||||
{ 0x000000bd, 0x0000001c },
|
||||
{ 0x00061096, 0x00000018 },
|
||||
{ 0x844075bd, 0x00000002 },
|
||||
{ 0x00061095, 0x00000018 },
|
||||
{ 0x840075bb, 0x00000002 },
|
||||
{ 0x00061096, 0x00000018 },
|
||||
{ 0x844075bc, 0x00000002 },
|
||||
{ 0x000000c0, 0x00000004 },
|
||||
{ 0x804075bd, 0x00000002 },
|
||||
{ 0x800075bb, 0x00000002 },
|
||||
{ 0x804075bc, 0x00000002 },
|
||||
{ 0x00108000, 0x00000002 },
|
||||
{ 0x01400000, 0x00000002 },
|
||||
{ 0x006000c4, 0x0000000c },
|
||||
{ 0x20c07000, 0x00000020 },
|
||||
{ 0x000000c6, 0x00000012 },
|
||||
{ 0x00800000, 0x00000006 },
|
||||
{ 0x0080751d, 0x00000006 },
|
||||
{ 0x000025bb, 0x00000002 },
|
||||
{ 0x000040c0, 0x00000004 },
|
||||
{ 0x0000775c, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00661000, 0x00000002 },
|
||||
{ 0x0460275d, 0x00000020 },
|
||||
{ 0x00004000, 0000000000 },
|
||||
{ 0x00007999, 0x00000002 },
|
||||
{ 0x00a05000, 0x00000002 },
|
||||
{ 0x00661000, 0x00000002 },
|
||||
{ 0x0460299b, 0x00000020 },
|
||||
{ 0x00004000, 0000000000 },
|
||||
{ 0x01e00830, 0x00000002 },
|
||||
{ 0x21007000, 0000000000 },
|
||||
{ 0x00005000, 0x00000002 },
|
||||
{ 0x00038042, 0x00000002 },
|
||||
{ 0x040025e0, 0x00000002 },
|
||||
{ 0x000075e1, 0000000000 },
|
||||
{ 0x00000001, 0000000000 },
|
||||
{ 0x000380d9, 0x00000002 },
|
||||
{ 0x04007394, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
};
|
||||
|
||||
// r300 microcode
|
||||
static const uint32 r300_cp_microcode[][2] = {
|
||||
{ 0x4200e000, 0000000000 },
|
||||
{ 0x4000e000, 0000000000 },
|
||||
{ 0x000000af, 0x00000008 },
|
||||
{ 0x000000b3, 0x00000008 },
|
||||
{ 0x6c5a504f, 0000000000 },
|
||||
{ 0x4f4f497a, 0000000000 },
|
||||
{ 0x5a578288, 0000000000 },
|
||||
{ 0x4f91906a, 0000000000 },
|
||||
{ 0x4f4f4f4f, 0000000000 },
|
||||
{ 0x4fe24f44, 0000000000 },
|
||||
{ 0x4f9c9c9c, 0000000000 },
|
||||
{ 0xdc4f4fde, 0000000000 },
|
||||
{ 0xa1cd4f4f, 0000000000 },
|
||||
{ 0xd29d9d9d, 0000000000 },
|
||||
{ 0x4f0f9fd7, 0000000000 },
|
||||
{ 0x000ca000, 0x00000004 },
|
||||
{ 0x000d0012, 0x00000038 },
|
||||
{ 0x0000e8b4, 0x00000004 },
|
||||
{ 0x000d0014, 0x00000038 },
|
||||
{ 0x0000e8b6, 0x00000004 },
|
||||
{ 0x000d0016, 0x00000038 },
|
||||
{ 0x0000e854, 0x00000004 },
|
||||
{ 0x000d0018, 0x00000038 },
|
||||
{ 0x0000e855, 0x00000004 },
|
||||
{ 0x000d001a, 0x00000038 },
|
||||
{ 0x0000e856, 0x00000004 },
|
||||
{ 0x000d001c, 0x00000038 },
|
||||
{ 0x0000e857, 0x00000004 },
|
||||
{ 0x000d001e, 0x00000038 },
|
||||
{ 0x0000e824, 0x00000004 },
|
||||
{ 0x000d0020, 0x00000038 },
|
||||
{ 0x0000e825, 0x00000004 },
|
||||
{ 0x000d0022, 0x00000038 },
|
||||
{ 0x0000e830, 0x00000004 },
|
||||
{ 0x000d0024, 0x00000038 },
|
||||
{ 0x0000f0c0, 0x00000004 },
|
||||
{ 0x000d0026, 0x00000038 },
|
||||
{ 0x0000f0c1, 0x00000004 },
|
||||
{ 0x000d0028, 0x00000038 },
|
||||
{ 0x0000f041, 0x00000004 },
|
||||
{ 0x000d002a, 0x00000038 },
|
||||
{ 0x0000f184, 0x00000004 },
|
||||
{ 0x000d002c, 0x00000038 },
|
||||
{ 0x0000f185, 0x00000004 },
|
||||
{ 0x000d002e, 0x00000038 },
|
||||
{ 0x0000f186, 0x00000004 },
|
||||
{ 0x000d0030, 0x00000038 },
|
||||
{ 0x0000f187, 0x00000004 },
|
||||
{ 0x000d0032, 0x00000038 },
|
||||
{ 0x0000f180, 0x00000004 },
|
||||
{ 0x000d0034, 0x00000038 },
|
||||
{ 0x0000f393, 0x00000004 },
|
||||
{ 0x000d0036, 0x00000038 },
|
||||
{ 0x0000f38a, 0x00000004 },
|
||||
{ 0x000d0038, 0x00000038 },
|
||||
{ 0x0000f38e, 0x00000004 },
|
||||
{ 0x0000e821, 0x00000004 },
|
||||
{ 0x0140a000, 0x00000004 },
|
||||
{ 0x00000043, 0x00000018 },
|
||||
{ 0x00cce800, 0x00000004 },
|
||||
{ 0x001b0001, 0x00000004 },
|
||||
{ 0x08004800, 0x00000004 },
|
||||
{ 0x001b0001, 0x00000004 },
|
||||
{ 0x08004800, 0x00000004 },
|
||||
{ 0x001b0001, 0x00000004 },
|
||||
{ 0x08004800, 0x00000004 },
|
||||
{ 0x0000003a, 0x00000008 },
|
||||
{ 0x0000a000, 0000000000 },
|
||||
{ 0x02c0a000, 0x00000004 },
|
||||
{ 0x000ca000, 0x00000004 },
|
||||
{ 0x00130000, 0x00000004 },
|
||||
{ 0x000c2000, 0x00000004 },
|
||||
{ 0xc980c045, 0x00000008 },
|
||||
{ 0x2000451d, 0x00000004 },
|
||||
{ 0x0000e580, 0x00000004 },
|
||||
{ 0x000ce581, 0x00000004 },
|
||||
{ 0x08004580, 0x00000004 },
|
||||
{ 0x000ce581, 0x00000004 },
|
||||
{ 0x0000004c, 0x00000008 },
|
||||
{ 0x0000a000, 0000000000 },
|
||||
{ 0x000c2000, 0x00000004 },
|
||||
{ 0x0000e50e, 0x00000004 },
|
||||
{ 0x00032000, 0x00000004 },
|
||||
{ 0x00022056, 0x00000028 },
|
||||
{ 0x00000056, 0x00000024 },
|
||||
{ 0x0800450f, 0x00000004 },
|
||||
{ 0x0000a050, 0x00000008 },
|
||||
{ 0x0000e565, 0x00000004 },
|
||||
{ 0x0000e566, 0x00000004 },
|
||||
{ 0x00000057, 0x00000008 },
|
||||
{ 0x03cca5b4, 0x00000004 },
|
||||
{ 0x05432000, 0x00000004 },
|
||||
{ 0x00022000, 0x00000004 },
|
||||
{ 0x4ccce063, 0x00000030 },
|
||||
{ 0x08274565, 0x00000004 },
|
||||
{ 0x00000063, 0x00000030 },
|
||||
{ 0x08004564, 0x00000004 },
|
||||
{ 0x0000e566, 0x00000004 },
|
||||
{ 0x0000005a, 0x00000008 },
|
||||
{ 0x00802066, 0x00000010 },
|
||||
{ 0x00202000, 0x00000004 },
|
||||
{ 0x001b00ff, 0x00000004 },
|
||||
{ 0x01000069, 0x00000010 },
|
||||
{ 0x001f2000, 0x00000004 },
|
||||
{ 0x001c00ff, 0x00000004 },
|
||||
{ 0000000000, 0x0000000c },
|
||||
{ 0x00000085, 0x00000030 },
|
||||
{ 0x0000005a, 0x00000008 },
|
||||
{ 0x0000e576, 0x00000004 },
|
||||
{ 0x000ca000, 0x00000004 },
|
||||
{ 0x00012000, 0x00000004 },
|
||||
{ 0x00082000, 0x00000004 },
|
||||
{ 0x1800650e, 0x00000004 },
|
||||
{ 0x00092000, 0x00000004 },
|
||||
{ 0x000a2000, 0x00000004 },
|
||||
{ 0x000f0000, 0x00000004 },
|
||||
{ 0x00400000, 0x00000004 },
|
||||
{ 0x00000079, 0x00000018 },
|
||||
{ 0x0000e563, 0x00000004 },
|
||||
{ 0x00c0e5f9, 0x000000c2 },
|
||||
{ 0x0000006e, 0x00000008 },
|
||||
{ 0x0000a06e, 0x00000008 },
|
||||
{ 0x0000e576, 0x00000004 },
|
||||
{ 0x0000e577, 0x00000004 },
|
||||
{ 0x0000e50e, 0x00000004 },
|
||||
{ 0x0000e50f, 0x00000004 },
|
||||
{ 0x0140a000, 0x00000004 },
|
||||
{ 0x0000007c, 0x00000018 },
|
||||
{ 0x00c0e5f9, 0x000000c2 },
|
||||
{ 0x0000007c, 0x00000008 },
|
||||
{ 0x0014e50e, 0x00000004 },
|
||||
{ 0x0040e50f, 0x00000004 },
|
||||
{ 0x00c0007f, 0x00000008 },
|
||||
{ 0x0000e570, 0x00000004 },
|
||||
{ 0x0000e571, 0x00000004 },
|
||||
{ 0x0000e572, 0x0000000c },
|
||||
{ 0x0000a000, 0x00000004 },
|
||||
{ 0x0140a000, 0x00000004 },
|
||||
{ 0x0000e568, 0x00000004 },
|
||||
{ 0x000c2000, 0x00000004 },
|
||||
{ 0x00000089, 0x00000018 },
|
||||
{ 0x000b0000, 0x00000004 },
|
||||
{ 0x18c0e562, 0x00000004 },
|
||||
{ 0x0000008b, 0x00000008 },
|
||||
{ 0x00c0008a, 0x00000008 },
|
||||
{ 0x000700e4, 0x00000004 },
|
||||
{ 0x00000097, 0x00000038 },
|
||||
{ 0x000ca099, 0x00000030 },
|
||||
{ 0x080045bb, 0x00000004 },
|
||||
{ 0x000c209a, 0x00000030 },
|
||||
{ 0x0800e5bc, 0000000000 },
|
||||
{ 0x0000e5bb, 0x00000004 },
|
||||
{ 0x0000e5bc, 0000000000 },
|
||||
{ 0x00120000, 0x0000000c },
|
||||
{ 0x00120000, 0x00000004 },
|
||||
{ 0x001b0002, 0x0000000c },
|
||||
{ 0x0000a000, 0x00000004 },
|
||||
{ 0x0000e821, 0x00000004 },
|
||||
{ 0x0000e800, 0000000000 },
|
||||
{ 0x0000e821, 0x00000004 },
|
||||
{ 0x0000e82e, 0000000000 },
|
||||
{ 0x02cca000, 0x00000004 },
|
||||
{ 0x00140000, 0x00000004 },
|
||||
{ 0x000ce1cc, 0x00000004 },
|
||||
{ 0x050de1cd, 0x00000004 },
|
||||
{ 0x000000a7, 0x00000020 },
|
||||
{ 0x4200e000, 0000000000 },
|
||||
{ 0x000000ae, 0x00000038 },
|
||||
{ 0x000ca000, 0x00000004 },
|
||||
{ 0x00140000, 0x00000004 },
|
||||
{ 0x000c2000, 0x00000004 },
|
||||
{ 0x00160000, 0x00000004 },
|
||||
{ 0x700ce000, 0x00000004 },
|
||||
{ 0x001400aa, 0x00000008 },
|
||||
{ 0x4000e000, 0000000000 },
|
||||
{ 0x02400000, 0x00000004 },
|
||||
{ 0x400ee000, 0x00000004 },
|
||||
{ 0x02400000, 0x00000004 },
|
||||
{ 0x4000e000, 0000000000 },
|
||||
{ 0x000c2000, 0x00000004 },
|
||||
{ 0x0240e51b, 0x00000004 },
|
||||
{ 0x0080e50a, 0x00000005 },
|
||||
{ 0x0080e50b, 0x00000005 },
|
||||
{ 0x00220000, 0x00000004 },
|
||||
{ 0x000700e4, 0x00000004 },
|
||||
{ 0x000000c1, 0x00000038 },
|
||||
{ 0x000c209a, 0x00000030 },
|
||||
{ 0x0880e5bd, 0x00000005 },
|
||||
{ 0x000c2099, 0x00000030 },
|
||||
{ 0x0800e5bb, 0x00000005 },
|
||||
{ 0x000c209a, 0x00000030 },
|
||||
{ 0x0880e5bc, 0x00000005 },
|
||||
{ 0x000000c4, 0x00000008 },
|
||||
{ 0x0080e5bd, 0x00000005 },
|
||||
{ 0x0000e5bb, 0x00000005 },
|
||||
{ 0x0080e5bc, 0x00000005 },
|
||||
{ 0x00210000, 0x00000004 },
|
||||
{ 0x02800000, 0x00000004 },
|
||||
{ 0x00c000c8, 0x00000018 },
|
||||
{ 0x4180e000, 0x00000040 },
|
||||
{ 0x000000ca, 0x00000024 },
|
||||
{ 0x01000000, 0x0000000c },
|
||||
{ 0x0100e51d, 0x0000000c },
|
||||
{ 0x000045bb, 0x00000004 },
|
||||
{ 0x000080c4, 0x00000008 },
|
||||
{ 0x0000f3ce, 0x00000004 },
|
||||
{ 0x0140a000, 0x00000004 },
|
||||
{ 0x00cc2000, 0x00000004 },
|
||||
{ 0x08c053cf, 0x00000040 },
|
||||
{ 0x00008000, 0000000000 },
|
||||
{ 0x0000f3d2, 0x00000004 },
|
||||
{ 0x0140a000, 0x00000004 },
|
||||
{ 0x00cc2000, 0x00000004 },
|
||||
{ 0x08c053d3, 0x00000040 },
|
||||
{ 0x00008000, 0000000000 },
|
||||
{ 0x0000f39d, 0x00000004 },
|
||||
{ 0x0140a000, 0x00000004 },
|
||||
{ 0x00cc2000, 0x00000004 },
|
||||
{ 0x08c0539e, 0x00000040 },
|
||||
{ 0x00008000, 0000000000 },
|
||||
{ 0x03c00830, 0x00000004 },
|
||||
{ 0x4200e000, 0000000000 },
|
||||
{ 0x0000a000, 0x00000004 },
|
||||
{ 0x200045e0, 0x00000004 },
|
||||
{ 0x0000e5e1, 0000000000 },
|
||||
{ 0x00000001, 0000000000 },
|
||||
{ 0x000700e1, 0x00000004 },
|
||||
{ 0x0800e394, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
{ 0000000000, 0000000000 },
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Hardware cursor support
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "mmio.h"
|
||||
#include "crtc_regs.h"
|
||||
|
||||
static void doShowCursor( accelerator_info *ai, virtual_port *port );
|
||||
static void moveOneCursor( accelerator_info *ai, virtual_port *port, int x, int y );
|
||||
|
||||
// set standard foreground/background colours
|
||||
void Radeon_SetCursorColors( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
if( port->is_crtc2 ) {
|
||||
Radeon_WriteRegCP( ai, RADEON_CUR2_CLR0, 0xffffff );
|
||||
Radeon_WriteRegCP( ai, RADEON_CUR2_CLR1, 0 );
|
||||
} else {
|
||||
Radeon_WriteRegCP( ai, RADEON_CUR_CLR0, 0xffffff );
|
||||
Radeon_WriteRegCP( ai, RADEON_CUR_CLR1, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
// public function to set shape of cursor
|
||||
status_t SET_CURSOR_SHAPE( uint16 width, uint16 height, uint16 hot_x, uint16 hot_y,
|
||||
uint8 *andMask, uint8 *xorMask)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
uint8 *fb_cursor = vc->cursor.data;
|
||||
int row, col_byte;
|
||||
|
||||
/* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */
|
||||
/* if( width != 16 || height != 16 )
|
||||
return B_ERROR;*/
|
||||
|
||||
if( hot_x >= width || hot_y >= height )
|
||||
return B_ERROR;
|
||||
|
||||
// TBD: should we sync here? I'd say so, but if I fail, we deadlock
|
||||
|
||||
vc->cursor.hot_x = hot_x;
|
||||
vc->cursor.hot_y = hot_y;
|
||||
|
||||
for( row = 0; row < 64; ++row ) {
|
||||
for( col_byte = 0; col_byte < 64 / 8; ++col_byte ) {
|
||||
if( row < height && col_byte < (width + 7) / 8 ) {
|
||||
fb_cursor[row * 64/8 * 2 + col_byte] = *andMask++;
|
||||
fb_cursor[row * 64/8 * 2 + col_byte + 64/8] = *xorMask++;
|
||||
} else {
|
||||
fb_cursor[row * 64/8 * 2 + col_byte] = 0xff;
|
||||
fb_cursor[row * 64/8 * 2 + col_byte + 64/8] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// public function to move cursor
|
||||
void MOVE_CURSOR(uint16 x, uint16 y)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
bool move_screen = false;
|
||||
uint16 hds, vds;
|
||||
// int xorigin, yorigin, x1, y1;
|
||||
|
||||
// alignment mask for horizontal position
|
||||
uint16 h_adjust = 7;
|
||||
|
||||
ACQUIRE_BEN( ai->si->engine.lock );
|
||||
|
||||
hds = vc->mode.h_display_start;
|
||||
vds = vc->mode.v_display_start;
|
||||
|
||||
// clamp cursor (negative positions are impossible due to uint16)
|
||||
if (x >= vc->mode.virtual_width)
|
||||
x = vc->mode.virtual_width - 1;
|
||||
if (y >= vc->mode.virtual_height)
|
||||
y = vc->mode.virtual_height - 1;
|
||||
|
||||
// if scrolling enabled, i.e. we have a larger virtual screen,
|
||||
// pan display accordingly
|
||||
if( vc->scroll ) {
|
||||
if( x >= (vc->mode.timing.h_display + hds) ) {
|
||||
hds = ((x - vc->mode.timing.h_display) + 1 + h_adjust) & ~h_adjust;
|
||||
move_screen = true;
|
||||
} else if( x < hds ) {
|
||||
hds = x & ~h_adjust;
|
||||
move_screen = true;
|
||||
}
|
||||
if( y >= (vc->mode.timing.v_display + vds) ) {
|
||||
vds = y - vc->mode.timing.v_display + 1;
|
||||
move_screen = true;
|
||||
} else if( y < vds ) {
|
||||
vds = y;
|
||||
move_screen = true;
|
||||
}
|
||||
|
||||
if( move_screen )
|
||||
Radeon_MoveDisplay( ai, hds, vds );
|
||||
}
|
||||
|
||||
// adjust according to virtual screen position
|
||||
x -= hds;
|
||||
y -= vds;
|
||||
|
||||
// go
|
||||
moveOneCursor( ai, &vc->ports[0], x, y );
|
||||
if( vc->independant_ports > 1 )
|
||||
moveOneCursor( ai, &vc->ports[1], x, y );
|
||||
|
||||
RELEASE_BEN( ai->si->engine.lock );
|
||||
}
|
||||
|
||||
|
||||
// public function to show cursor
|
||||
void SHOW_CURSOR( bool is_visible )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
// ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
// this is the public statement
|
||||
vc->cursor.is_visible = is_visible;
|
||||
|
||||
// the following functions take also care to not
|
||||
// show the cursor if it's on the other port
|
||||
doShowCursor( ai, &vc->ports[0] );
|
||||
if( vc->independant_ports > 1 )
|
||||
doShowCursor( ai, &vc->ports[1] );
|
||||
|
||||
// RELEASE_BEN( si->engine.lock );
|
||||
}
|
||||
|
||||
|
||||
// move cursor on one port
|
||||
// main_port - common data is stored here
|
||||
void moveOneCursor( accelerator_info *ai, virtual_port *port, int x, int y )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
int xorigin, yorigin;
|
||||
bool prev_state;
|
||||
|
||||
// adjust according to relative screen position
|
||||
x -= port->rel_x;
|
||||
y -= port->rel_y;
|
||||
|
||||
// and to hot spot
|
||||
x -= vc->cursor.hot_x;
|
||||
y -= vc->cursor.hot_y;
|
||||
|
||||
// check whether the cursor is (partially) visible on this screen
|
||||
prev_state = port->cursor_on_screen;
|
||||
port->cursor_on_screen = true;
|
||||
|
||||
// in theory, cursor can be up to 64 pixels off screen,
|
||||
// but there were display errors
|
||||
if( y > port->mode.timing.v_display ||
|
||||
x > port->mode.timing.h_display ||
|
||||
x <= -16 || y <= -16 )
|
||||
{
|
||||
port->cursor_on_screen = false;
|
||||
}
|
||||
|
||||
if( prev_state != port->cursor_on_screen )
|
||||
doShowCursor( ai, port );
|
||||
|
||||
if( !port->cursor_on_screen )
|
||||
return;
|
||||
|
||||
// if upper-left corner of cursor is outside of
|
||||
// screen, we have to use special registers to clip it
|
||||
xorigin = 0;
|
||||
yorigin = 0;
|
||||
|
||||
if( x < 0 )
|
||||
xorigin = -x;
|
||||
|
||||
if( y < 0 )
|
||||
yorigin = -y;
|
||||
|
||||
Radeon_WaitForFifo( ai, 3 );
|
||||
|
||||
if( port->is_crtc2 ) {
|
||||
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_OFF, RADEON_CUR2_LOCK
|
||||
| (xorigin << 16)
|
||||
| yorigin );
|
||||
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_POSN, RADEON_CUR2_LOCK
|
||||
| ((xorigin ? 0 : x) << 16)
|
||||
| (yorigin ? 0 : y) );
|
||||
OUTREG( ai->regs, RADEON_CUR2_OFFSET,
|
||||
vc->cursor.fb_offset + xorigin + yorigin * 16 );
|
||||
|
||||
} else {
|
||||
OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_OFF, RADEON_CUR_LOCK
|
||||
| (xorigin << 16)
|
||||
| yorigin );
|
||||
OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_POSN, RADEON_CUR_LOCK
|
||||
| ((xorigin ? 0 : x) << 16)
|
||||
| (yorigin ? 0 : y) );
|
||||
OUTREG( ai->regs, RADEON_CUR_OFFSET,
|
||||
vc->cursor.fb_offset + xorigin + yorigin * 16 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// show cursor on one port, depending on official whishes and whether
|
||||
// cursor is located on this subscreen
|
||||
void doShowCursor( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
uint32 tmp;
|
||||
|
||||
if( port->is_crtc2 ) {
|
||||
tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL );
|
||||
|
||||
if( vc->cursor.is_visible && port->cursor_on_screen )
|
||||
tmp |= RADEON_CRTC2_CUR_EN;
|
||||
else
|
||||
tmp &= ~RADEON_CRTC2_CUR_EN;
|
||||
|
||||
Radeon_WaitForFifo( ai, 1 );
|
||||
OUTREG( ai->regs, RADEON_CRTC2_GEN_CNTL, tmp );
|
||||
|
||||
} else {
|
||||
tmp = INREG( ai->regs, RADEON_CRTC_GEN_CNTL );
|
||||
|
||||
if( vc->cursor.is_visible && port->cursor_on_screen ) {
|
||||
tmp |= RADEON_CRTC_CUR_EN;
|
||||
} else {
|
||||
tmp &= ~RADEON_CRTC_CUR_EN;
|
||||
}
|
||||
|
||||
Radeon_WaitForFifo( ai, 1 );
|
||||
OUTREG( ai->regs, RADEON_CRTC_GEN_CNTL, tmp );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Hardware accelerator management
|
||||
|
||||
All accelerator commands go through the following steps:
|
||||
- accelerant adds command to CP buffer and updates CP write pointer
|
||||
- CP fetches command and sends it to MicroController
|
||||
- MicroController instructs 2D unit to execute command
|
||||
- 2D unit draws into 2D Destination Cache (DC)
|
||||
- 2D Destination Cache is drained to frame buffer
|
||||
|
||||
Whenever a token is required by BeOS, a command is queued to write
|
||||
the timestamp into Scratch Register 0. I haven't fully understand
|
||||
when and how coherancy is assured by Radeon, so I assume the following:
|
||||
- when the timestamp is written, all previous commands have been issued,
|
||||
i.e. they are read and executed by the microcontroller
|
||||
- to make sure previously issued 2D commands have been finished,
|
||||
a WAIT_2D_IDLECLEAN command is inserted before the scratch register
|
||||
write
|
||||
- to flush the destination cache, a RB2D_DC_FLUSH_ALL command is
|
||||
issued before the wait; I hope that the wait command also waits for
|
||||
the flush command, but I'm not sure about that
|
||||
|
||||
Remains the cache coherency problem. It you can set various bits in
|
||||
DSTCACHE_MODE register to assure that, but first I don't really understand
|
||||
them, and second I'm not sure which other caches/FIFO may make trouble.
|
||||
Especially, Be wants to use CPU and CP accesses in parallel. Hopefully,
|
||||
they don't interfere.
|
||||
|
||||
I know that the PAINT_MULTI commands makes trouble if you change the
|
||||
ROP to something else: CPU writes produce garbage in frame buffer for the
|
||||
next couple of accesses. Resetting the ROP to a simply copy helps, but
|
||||
I'm not sure what happens with concurrent CPU accesses to other areas
|
||||
of the frame buffer.
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "generic.h"
|
||||
#include "cp_regs.h"
|
||||
#include "rbbm_regs.h"
|
||||
#include "GlobalData.h"
|
||||
#include "mmio.h"
|
||||
|
||||
static engine_token radeon_engine_token = { 1, B_2D_ACCELERATION, NULL };
|
||||
|
||||
// public function: return number of hardware engine
|
||||
uint32 ACCELERANT_ENGINE_COUNT(void)
|
||||
{
|
||||
// hm, is there *any* card sporting more then
|
||||
// one hardware accelerator???
|
||||
return 1;
|
||||
}
|
||||
|
||||
// write current token into CP stream
|
||||
static void writeSyncToken( accelerator_info *ai )
|
||||
{
|
||||
uint32 buffer[6];
|
||||
uint idx = 0;
|
||||
|
||||
// don't write token if it hasn't changed since last write
|
||||
if( ai->si->engine.count == ai->si->engine.written )
|
||||
return;
|
||||
|
||||
// flush pending data
|
||||
buffer[idx++] = CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 );
|
||||
buffer[idx++] = RADEON_RB2D_DC_FLUSH_ALL;
|
||||
|
||||
// make sure commands are finished
|
||||
buffer[idx++] = CP_PACKET0( RADEON_WAIT_UNTIL, 0 );
|
||||
buffer[idx++] = RADEON_WAIT_2D_IDLECLEAN |
|
||||
RADEON_WAIT_3D_IDLECLEAN | RADEON_WAIT_HOST_IDLECLEAN;
|
||||
|
||||
// write scratch register
|
||||
buffer[idx++] = CP_PACKET0( RADEON_SCRATCH_REG0, 0 );
|
||||
buffer[idx++] = ai->si->engine.count;
|
||||
|
||||
ai->si->engine.written = ai->si->engine.count;
|
||||
|
||||
Radeon_SendCP( ai, buffer, idx );
|
||||
}
|
||||
|
||||
// public function: acquire engine for future use
|
||||
// capabilites - required 2D/3D capabilities of engine, ignored
|
||||
// max_wait - maximum time we want to wait (in ms?), ignored
|
||||
// st - when engine has been acquired, wait for this sync token
|
||||
// et - (out) specifier of the engine acquired
|
||||
status_t ACQUIRE_ENGINE( uint32 capabilities, uint32 max_wait,
|
||||
sync_token *st, engine_token **et )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
ACQUIRE_BEN( si->engine.lock)
|
||||
|
||||
if( si->active_vc != vc->id )
|
||||
Radeon_ActivateVirtualCard( ai );
|
||||
|
||||
// wait for sync
|
||||
if (st)
|
||||
SYNC_TO_TOKEN( st );
|
||||
|
||||
*et = &radeon_engine_token;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// public function: release accelerator
|
||||
// et - engine to release
|
||||
// st - (out) sync token to be filled out
|
||||
status_t RELEASE_ENGINE( engine_token *et, sync_token *st )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
// fill out sync token
|
||||
if (st) {
|
||||
writeSyncToken( ai );
|
||||
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
}
|
||||
|
||||
RELEASE_BEN( ai->si->engine.lock )
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// public function: wait until engine is idle
|
||||
// ??? which engine to wait for? Is there anyone using this function?
|
||||
void WAIT_ENGINE_IDLE(void)
|
||||
{
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
Radeon_Finish( ai );
|
||||
}
|
||||
|
||||
// public function: get sync token
|
||||
// et - engine to wait for
|
||||
// st - (out) sync token to be filled out
|
||||
status_t GET_SYNC_TOKEN( engine_token *et, sync_token *st )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
writeSyncToken( ai );
|
||||
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
|
||||
SHOW_FLOW( 4, "got counter=%d", si->engine.count );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// this is the same as the corresponding kernel function
|
||||
static void spin( uint32 delay )
|
||||
{
|
||||
bigtime_t start_time;
|
||||
|
||||
start_time = system_time();
|
||||
|
||||
while( system_time() - start_time < delay )
|
||||
;
|
||||
}
|
||||
|
||||
// public: sync to token
|
||||
// st - token to wait for
|
||||
status_t SYNC_TO_TOKEN( sync_token *st )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
bigtime_t start_time, sample_time;
|
||||
// status_t result;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
start_time = system_time();
|
||||
|
||||
while( 1 ) {
|
||||
SHOW_FLOW( 4, "passed counter=%d", *si->scratch_ptr );
|
||||
|
||||
// a bit nasty: counter is 64 bit, but we have 32 bit only,
|
||||
// this is a tricky calculation to handle wrap-arounds correctly
|
||||
/*if( (int32)(*si->scratch_ptr - st->counter) >= 0 )
|
||||
return B_OK;*/
|
||||
if( (int32)(INREG( ai->regs, RADEON_SCRATCH_REG0 ) - st->counter) >= 0 )
|
||||
return B_OK;
|
||||
|
||||
sample_time = system_time();
|
||||
|
||||
if( sample_time - start_time > 100000 )
|
||||
break;
|
||||
|
||||
// use exponential fall-off
|
||||
// in the beginning do busy-waiting, later on we let thread sleep
|
||||
// the micro-spin is used to reduce PCI load
|
||||
if( sample_time - start_time > 5000 )
|
||||
snooze( (sample_time - start_time) / 10 );
|
||||
else
|
||||
spin( 1 );
|
||||
}
|
||||
|
||||
// we could reset engine now, but caller doesn't need to acquire
|
||||
// engine before calling this function, so we either reset it
|
||||
// without sync (ouch!) or acquire engine first and risk deadlocking
|
||||
SHOW_ERROR( 0, "Failed waiting for token %d (active token: %d)",
|
||||
st->counter, INREG( ai->regs, RADEON_SCRATCH_REG0 )/**si->scratch_ptr*/ );
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Contains entry point to get public functions.
|
||||
(directly copied from sample driver)
|
||||
*/
|
||||
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
/*
|
||||
|
||||
The standard entry point. Given a uint32 feature identifier, this routine
|
||||
returns a pointer to the function that implements the feature. Some features
|
||||
require more information than just the identifier to select the proper
|
||||
function. The extra information (which is specific to the feature) is
|
||||
pointed at by the void *data parameter. By default, no extra information
|
||||
is available. Any extra information available to choose the function will be
|
||||
noted on a case by case below.
|
||||
|
||||
*/
|
||||
void * get_accelerant_hook(uint32 feature, void *data) {
|
||||
switch (feature) {
|
||||
/*
|
||||
These definitions are out of pure lazyness.
|
||||
*/
|
||||
#define HOOK(x) case B_##x: return (void *)x
|
||||
#define ZERO(x) case B_##x: return (void *)0
|
||||
|
||||
/*
|
||||
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
|
||||
subsequently called before any other hook is requested. All other feature
|
||||
hook selections can be predicated on variables assigned during the accelerant
|
||||
initialization process.
|
||||
*/
|
||||
/* initialization */
|
||||
HOOK(INIT_ACCELERANT);
|
||||
HOOK(CLONE_ACCELERANT);
|
||||
|
||||
HOOK(ACCELERANT_CLONE_INFO_SIZE);
|
||||
HOOK(GET_ACCELERANT_CLONE_INFO);
|
||||
HOOK(UNINIT_ACCELERANT);
|
||||
HOOK(GET_ACCELERANT_DEVICE_INFO);
|
||||
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
|
||||
|
||||
/* mode configuration */
|
||||
HOOK(ACCELERANT_MODE_COUNT);
|
||||
HOOK(GET_MODE_LIST);
|
||||
HOOK(PROPOSE_DISPLAY_MODE);
|
||||
HOOK(SET_DISPLAY_MODE);
|
||||
HOOK(GET_DISPLAY_MODE);
|
||||
HOOK(GET_FRAME_BUFFER_CONFIG);
|
||||
HOOK(GET_PIXEL_CLOCK_LIMITS);
|
||||
HOOK(MOVE_DISPLAY);
|
||||
HOOK(SET_INDEXED_COLORS);
|
||||
//HOOK(GET_TIMING_CONSTRAINTS);
|
||||
|
||||
HOOK(DPMS_CAPABILITIES);
|
||||
HOOK(DPMS_MODE);
|
||||
HOOK(SET_DPMS_MODE);
|
||||
|
||||
/* cursor managment */
|
||||
HOOK(SET_CURSOR_SHAPE);
|
||||
HOOK(MOVE_CURSOR);
|
||||
HOOK(SHOW_CURSOR);
|
||||
|
||||
/* synchronization */
|
||||
HOOK(ACCELERANT_ENGINE_COUNT);
|
||||
HOOK(ACQUIRE_ENGINE);
|
||||
HOOK(RELEASE_ENGINE);
|
||||
HOOK(WAIT_ENGINE_IDLE);
|
||||
HOOK(GET_SYNC_TOKEN);
|
||||
HOOK(SYNC_TO_TOKEN);
|
||||
|
||||
/*
|
||||
When requesting an acceleration hook, the calling application provides a
|
||||
pointer to the display_mode for which the acceleration function will be used.
|
||||
Depending on the engine architecture, you may choose to provide a different
|
||||
function to be used with each bit-depth. In the sample driver we return
|
||||
the same function all the time.
|
||||
*/
|
||||
/* 2D acceleration */
|
||||
HOOK(SCREEN_TO_SCREEN_BLIT);
|
||||
HOOK(FILL_RECTANGLE);
|
||||
HOOK(INVERT_RECTANGLE);
|
||||
HOOK(FILL_SPAN);
|
||||
|
||||
// overlay
|
||||
HOOK(OVERLAY_COUNT);
|
||||
HOOK(OVERLAY_SUPPORTED_SPACES);
|
||||
HOOK(OVERLAY_SUPPORTED_FEATURES);
|
||||
HOOK(ALLOCATE_OVERLAY_BUFFER);
|
||||
HOOK(RELEASE_OVERLAY_BUFFER);
|
||||
HOOK(GET_OVERLAY_CONSTRAINTS);
|
||||
HOOK(ALLOCATE_OVERLAY);
|
||||
HOOK(RELEASE_OVERLAY);
|
||||
HOOK(CONFIGURE_OVERLAY);
|
||||
#undef HOOK
|
||||
#undef ZERO
|
||||
}
|
||||
/*
|
||||
Return a null pointer for any feature we don't understand.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Public mode-specific info functions
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
|
||||
// public function: return current display mode
|
||||
status_t GET_DISPLAY_MODE( display_mode *current_mode )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
|
||||
// TBD: there is a race condition if someone else is just setting it
|
||||
// we won't lock up but return non-sense
|
||||
|
||||
*current_mode = vc->mode;
|
||||
|
||||
// we hide multi-monitor-mode because :-
|
||||
// - we want to look like an ordinary single-screen driver
|
||||
// - the multi-mode is already adapted to current screen configuration,
|
||||
// and the mode should be configuration-independant
|
||||
Radeon_HideMultiMode( vc, current_mode );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// public function: return configuration of frame buffer
|
||||
status_t GET_FRAME_BUFFER_CONFIG( frame_buffer_config *afb )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
|
||||
// TBD: race condition again
|
||||
|
||||
// easy again, as the last mode set stored the info in a convienient form
|
||||
*afb = vc->fbc;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// public function: return clock limits for given display mode
|
||||
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
|
||||
{
|
||||
// we ignore stuff like DVI/LCD restrictions -
|
||||
// they are handled automatically on set_display_mode
|
||||
uint32 total_pix = (uint32)dm->timing.h_total * (uint32)dm->timing.v_total;
|
||||
uint32 clock_limit = ai->si->pll.max_pll_freq * 10;
|
||||
|
||||
/* lower limit of about 48Hz vertical refresh */
|
||||
*low = (total_pix * 48L) / 1000L;
|
||||
if (*low > clock_limit)
|
||||
return B_ERROR;
|
||||
|
||||
*high = clock_limit;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the semaphore id that will be used to signal a vertical retrace
|
||||
occured.
|
||||
*/
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
|
||||
{
|
||||
// virtual_card *vc = ai->vc;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
The kernel driver created this for us. We don't know if the system is
|
||||
using real interrupts, or if we're faking it, and we don't care.
|
||||
If we choose not to support this at all, we'd just return B_ERROR here,
|
||||
and the user wouldn't get any kind of vertical retrace support.
|
||||
*/
|
||||
// with multi-monitor mode, we have two vertical blanks!
|
||||
// until we find a better solution, we always return virtual port 0,
|
||||
// which may be either physical port 0 or 1
|
||||
// int physical_port = vc->ports[0].physical_port;
|
||||
|
||||
//SHOW_INFO( 3, "semaphore: %x", ai->si->ports[physical_port].vblank );
|
||||
|
||||
//return ai->si->ports[physical_port].vblank;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Global data
|
||||
*/
|
||||
|
||||
|
||||
#include "GlobalData.h"
|
||||
|
||||
// the sample driver stores everything in global variables;
|
||||
// I dislike this idea as this makes supporting multiple graphics
|
||||
// card impossible; to be prepared, only the following variable is used
|
||||
accelerator_info *ai;
|
||||
|
||||
int debug_level_flow = 2;
|
||||
int debug_level_info = 4;
|
||||
int debug_level_error = 4;
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#if !defined(GLOBALDATA_H)
|
||||
#define GLOBALDATA_H
|
||||
|
||||
#ifndef _RADEON_ACCELERANT_H
|
||||
#include "radeon_accelerant.h"
|
||||
#endif
|
||||
|
||||
extern accelerator_info *ai;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Main init/uninit functions
|
||||
*/
|
||||
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "unistd.h"
|
||||
#include "sys/types.h"
|
||||
#include "sys/stat.h"
|
||||
#include "fcntl.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <malloc.h>
|
||||
|
||||
|
||||
// init data used by both primary and cloned accelerant
|
||||
// the_fd - file descriptor of kernel driver
|
||||
// accelerant_is_clone - if true, this is a cloned accelerant
|
||||
static status_t init_common( int the_fd, bool accelerant_is_clone )
|
||||
{
|
||||
status_t result;
|
||||
radeon_get_private_data gpd;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
ai = malloc( sizeof( *ai ));
|
||||
if( ai == NULL )
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset( ai, 0, sizeof( *ai ));
|
||||
|
||||
ai->accelerant_is_clone = accelerant_is_clone;
|
||||
ai->fd = the_fd;
|
||||
|
||||
// get basic info from driver
|
||||
gpd.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
|
||||
result = ioctl( ai->fd, RADEON_GET_PRIVATE_DATA, &gpd, sizeof(gpd) );
|
||||
if (result != B_OK) goto err;
|
||||
|
||||
ai->virtual_card_area = clone_area( "Radeon virtual card", (void **)&ai->vc, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, gpd.virtual_card_area );
|
||||
if( ai->virtual_card_area < 0 ) {
|
||||
result = ai->virtual_card_area;
|
||||
goto err;
|
||||
}
|
||||
ai->shared_info_area = clone_area("Radeon shared info", (void **)&ai->si, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
|
||||
if( ai->shared_info_area < 0 ) {
|
||||
result = ai->shared_info_area;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ai->regs_area = clone_area("Radeon regs area", (void **)&ai->regs, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, ai->si->regs_area);
|
||||
if( ai->regs_area < 0 ) {
|
||||
result = ai->regs_area;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
delete_area( ai->shared_info_area );
|
||||
err2:
|
||||
delete_area( ai->virtual_card_area );
|
||||
err:
|
||||
free( ai );
|
||||
return result;
|
||||
}
|
||||
|
||||
// clean up data common to both primary and cloned accelerant
|
||||
static void uninit_common( void )
|
||||
{
|
||||
delete_area( ai->regs_area );
|
||||
delete_area( ai->shared_info_area );
|
||||
delete_area( ai->virtual_card_area );
|
||||
|
||||
ai->regs_area = ai->shared_info_area = ai->virtual_card_area = 0;
|
||||
|
||||
ai->regs = 0;
|
||||
ai->si = 0;
|
||||
ai->vc = 0;
|
||||
|
||||
// close the file handle ONLY if we're the clone
|
||||
// (this is what Be tells us ;)
|
||||
if( ai->accelerant_is_clone )
|
||||
close( ai->fd );
|
||||
|
||||
free( ai );
|
||||
}
|
||||
|
||||
// public function: init primary accelerant
|
||||
// the_fd - file handle of kernel driver
|
||||
status_t INIT_ACCELERANT( int the_fd )
|
||||
{
|
||||
shared_info *si;
|
||||
virtual_card *vc;
|
||||
status_t result;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
result = init_common( the_fd, 0 );
|
||||
if (result != B_OK)
|
||||
goto err;
|
||||
|
||||
si = ai->si;
|
||||
vc = ai->vc;
|
||||
|
||||
// init Command Processor
|
||||
result = Radeon_InitCP( ai );
|
||||
if( result != B_OK )
|
||||
goto err2;
|
||||
|
||||
// this isn't the best place, but has to be done sometime
|
||||
Radeon_ReadSettings( vc );
|
||||
|
||||
// read FP info via DDC
|
||||
// (ignore result - if it fails we fall back to BIOS detection)
|
||||
if( si->fp_port.disp_type == dt_dvi_1 )
|
||||
Radeon_ReadFPEDID( ai, si );
|
||||
|
||||
// create list of supported modes
|
||||
result = Radeon_CreateModeList( si );
|
||||
if (result != B_OK)
|
||||
goto err3;
|
||||
|
||||
/* init the shared semaphore */
|
||||
INIT_BEN( "Radeon engine", si->engine.lock );
|
||||
|
||||
// init engine sync token
|
||||
// (count of issued parameters or commands)
|
||||
si->engine.last_idle = si->engine.count = 0;
|
||||
// set last written count to be very old, so it must be written on first use
|
||||
// (see writeSyncToken)
|
||||
si->engine.written = -1;
|
||||
|
||||
// init overlay
|
||||
si->overlay_mgr.token = 0;
|
||||
si->overlay_mgr.inuse = 0;
|
||||
|
||||
// mark overlay as inactive
|
||||
si->active_overlay.port = -1;
|
||||
si->pending_overlay.port = -1;
|
||||
|
||||
// reset list of allocated overlays
|
||||
vc->overlay_buffers = NULL;
|
||||
|
||||
// everything else is initialized upon set_display_mode
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
err2:
|
||||
uninit_common();
|
||||
err:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// public function: return size of clone info
|
||||
ssize_t ACCELERANT_CLONE_INFO_SIZE( void )
|
||||
{
|
||||
// clone info is device name, so return its maximum size
|
||||
return MAX_RADEON_DEVICE_NAME_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
// public function: return clone info
|
||||
// data - buffer to contain info (allocated by caller)
|
||||
void GET_ACCELERANT_CLONE_INFO( void *data )
|
||||
{
|
||||
radeon_device_name dn;
|
||||
status_t result;
|
||||
|
||||
// clone info is device name - ask device driver
|
||||
dn.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
dn.name = (char *)data;
|
||||
|
||||
result = ioctl( ai->fd, RADEON_DEVICE_NAME, &dn, sizeof(dn) );
|
||||
}
|
||||
|
||||
// public function: init cloned accelerant
|
||||
// data - clone info from get_accelerant_clone_info
|
||||
status_t CLONE_ACCELERANT( void *data )
|
||||
{
|
||||
status_t result;
|
||||
char path[MAXPATHLEN];
|
||||
int fd;
|
||||
|
||||
// create full device name
|
||||
strcpy(path, "/dev");
|
||||
strcat(path, (const char *)data);
|
||||
|
||||
// open device; according to Be, permissions aren't important
|
||||
// this will probably change once access right are checked properly
|
||||
fd = open(path, B_READ_WRITE);
|
||||
if( fd < 0 )
|
||||
return fd;
|
||||
|
||||
result = init_common( fd, 1 );
|
||||
if( result != B_OK )
|
||||
goto err1;
|
||||
|
||||
// get (cloned) copy of supported display modes
|
||||
result = ai->mode_list_area = clone_area(
|
||||
"Radeon cloned display_modes", (void **)&ai->mode_list,
|
||||
B_ANY_ADDRESS, B_READ_AREA, ai->si->mode_list_area );
|
||||
if (result < B_OK)
|
||||
goto err2;
|
||||
|
||||
return B_OK;
|
||||
|
||||
err2:
|
||||
uninit_common();
|
||||
err1:
|
||||
close( fd );
|
||||
return result;
|
||||
}
|
||||
|
||||
// public function: uninit primary or cloned accelerant
|
||||
void UNINIT_ACCELERANT( void )
|
||||
{
|
||||
// TBD:
|
||||
// we should put accelerator into stable state first -
|
||||
// on my Laptop, you never can boot Windows/Linux after shutting
|
||||
// down BeOS; if both ports have been used, even the BIOS screen
|
||||
// is completely messed up
|
||||
|
||||
// cloned accelerants have mode_list cloned, so deleting is OK
|
||||
// primary accelerant owns mode list, so deleting is OK as well
|
||||
delete_area( ai->mode_list_area );
|
||||
ai->mode_list = 0;
|
||||
|
||||
uninit_common();
|
||||
}
|
||||
|
||||
// public function: get some info about graphics card
|
||||
status_t GET_ACCELERANT_DEVICE_INFO( accelerant_device_info *di )
|
||||
{
|
||||
// is there anyone using it?
|
||||
|
||||
// TBD: everything apart from memsize
|
||||
di->version = B_ACCELERANT_VERSION;
|
||||
strcpy( di->name, "Radeon" );
|
||||
strcpy( di->chipset, "Radeon" );
|
||||
strcpy( di->serial_no, "None" );
|
||||
|
||||
di->memory = ai->si->local_mem_size;
|
||||
|
||||
// TBD: is max PLL speed really equal to max DAC speed?
|
||||
di->dac_speed = ai->si->pll.max_pll_freq;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
SubDir OBOS_TOP src add-ons accelerants radeon ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics radeon ] ;
|
||||
|
||||
|
||||
Addon radeon.accelerant : accelerants :
|
||||
Acceleration.c
|
||||
CP.c
|
||||
Cursor.c
|
||||
EngineManagment.c
|
||||
GetAccelerantHook.c
|
||||
GetModeInfo.c
|
||||
GlobalData.c
|
||||
InitAccelerant.c
|
||||
ProposeDisplayMode.c
|
||||
SetDisplayMode.c
|
||||
crtc.c
|
||||
dpms.c
|
||||
engine_sync.c
|
||||
flat_panel.c
|
||||
multimon.c
|
||||
overlay.c
|
||||
overlay_management.c
|
||||
pll.c
|
||||
settings.cpp
|
||||
utils.c
|
||||
log_coll.c
|
||||
log_dump.c
|
||||
ddc.c
|
||||
dump_edid.c
|
||||
edid.c
|
||||
i2c.c
|
||||
;
|
||||
|
||||
Package openbeos-radeon-cvs :
|
||||
radeon.accelerant :
|
||||
boot home config add-ons accelerants ;
|
||||
|
||||
Depends radeon.accelerant : radeon.driver ;
|
||||
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Everything concerning getting/testing display modes
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "generic.h"
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "GlobalData.h"
|
||||
|
||||
#include "crtc_regs.h"
|
||||
#include "utils.h"
|
||||
|
||||
// standard mode list
|
||||
// all drivers contain this list - this should really be moved to
|
||||
// something like the screen preferences panel
|
||||
|
||||
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
|
||||
#define MODE_FLAGS (B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS | B_SUPPORTS_OVERLAYS)
|
||||
//#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
|
||||
|
||||
static const display_mode base_mode_list[] = {
|
||||
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
|
||||
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
|
||||
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
|
||||
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
|
||||
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
|
||||
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
|
||||
{ { 25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS}, /* 640x400 - www.epanorama.net/documents/pc/vga_timing.html) */
|
||||
{ { 25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS}, /* 640x350 - www.epanorama.net/documents/pc/vga_timing.html) */
|
||||
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
|
||||
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
|
||||
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
|
||||
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */
|
||||
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
|
||||
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
|
||||
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
|
||||
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
|
||||
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
|
||||
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
|
||||
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
|
||||
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
|
||||
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
|
||||
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
|
||||
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
|
||||
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
|
||||
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
|
||||
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
|
||||
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
|
||||
};
|
||||
|
||||
status_t Radeon_ProposeDisplayMode( shared_info *si, physical_port *port,
|
||||
pll_info *pll, display_mode *target,
|
||||
const display_mode *low, const display_mode *high );
|
||||
void Radeon_DisposeModeList( shared_info *si );
|
||||
|
||||
|
||||
// convert Be colour space in Radeon data type
|
||||
// returns true, if supported colour space
|
||||
// space - Be colour space
|
||||
// format - (out) Radeon data type
|
||||
// bpp - (out) bytes per pixel
|
||||
bool Radeon_GetFormat( int space, int *format, int *bpp )
|
||||
{
|
||||
switch( space ) {
|
||||
/*case 4: format = 1; bytpp = 0; break;*/
|
||||
case B_CMAP8: *format = 2; *bpp = 1; break;
|
||||
case B_RGB15_LITTLE: *format = 3; *bpp = 2; break; /* 555 */
|
||||
case B_RGB16_LITTLE: *format = 4; *bpp = 2; break; /* 565 */
|
||||
case B_RGB24_LITTLE: *format = 5; *bpp = 3; break; /* RGB */
|
||||
case B_RGB32_LITTLE: *format = 6; *bpp = 4; break; /* xRGB */
|
||||
default:
|
||||
SHOW_ERROR( 1, "Unsupported color space (%d)", space );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// macros to convert between register values and pixels
|
||||
#define H_DISPLAY_2REG( a ) ((a) / 8 - 1)
|
||||
#define H_DISPLAY_2PIX( a ) (((a) + 1) * 8)
|
||||
#define H_TOTAL_2REG( a ) ((a) / 8 - 1)
|
||||
#define H_TOTAL_2PIX( a ) (((a) + 1) * 8)
|
||||
#define H_SSTART_2REG( a ) ((a) - 8 + h_sync_fudge)
|
||||
#define H_SSTART_2PIX( a ) ((a) + 8 - h_sync_fudge)
|
||||
#define H_SWID_2REG( a ) ((a) / 8)
|
||||
#define H_SWID_2PIX( a ) ((a) * 8)
|
||||
|
||||
#define V_2REG( a ) ((a) - 1)
|
||||
#define V_2PIX( a ) ((a) + 1)
|
||||
|
||||
/*
|
||||
Validate a target display mode is both
|
||||
a) a valid display mode for this device and
|
||||
b) falls between the contraints imposed by "low" and "high"
|
||||
|
||||
If the mode is not (or cannot) be made valid for this device, return B_ERROR.
|
||||
If a valid mode can be constructed, but it does not fall within the limits,
|
||||
return B_BAD_VALUE.
|
||||
If the mode is both valid AND falls within the limits, return B_OK.
|
||||
*/
|
||||
status_t Radeon_ProposeDisplayMode( shared_info *si, physical_port *port,
|
||||
pll_info *pll, display_mode *target,
|
||||
const display_mode *low, const display_mode *high )
|
||||
{
|
||||
status_t result = B_OK;
|
||||
|
||||
uint64 target_refresh;
|
||||
bool want_same_width, want_same_height;
|
||||
int format, bpp;
|
||||
uint32 row_bytes;
|
||||
int eff_virtual_width;
|
||||
// display_type_e disp_type;
|
||||
|
||||
// save refresh rate - we want to leave this (artifical) value untouched
|
||||
// don't use floating point, we are in kernel mode
|
||||
target_refresh =
|
||||
(((uint64)target->timing.pixel_clock * 1000) << FIX_SHIFT) /
|
||||
((uint64)target->timing.h_total * target->timing.v_total);
|
||||
|
||||
want_same_width = target->timing.h_display == target->virtual_width;
|
||||
want_same_height = target->timing.v_display == target->virtual_height;
|
||||
|
||||
if( !Radeon_GetFormat( target->space, &format, &bpp ))
|
||||
return B_ERROR;
|
||||
|
||||
// for flat panels, check maximum resolution;
|
||||
// all the other tricks (like fixed resolution and resulting scaling)
|
||||
// are done automagically by set_display_mode
|
||||
if( port->disp_type == dt_dvi_1 || port->disp_type == dt_lvds ) {
|
||||
if( target->timing.h_display > si->fp_port.panel_xres )
|
||||
target->timing.h_display = si->fp_port.panel_xres;
|
||||
|
||||
if( target->timing.v_display > si->fp_port.panel_yres )
|
||||
target->timing.v_display = si->fp_port.panel_yres;
|
||||
}
|
||||
|
||||
// validate horizontal timings
|
||||
{
|
||||
int h_sync_fudge, h_display, h_sync_start, h_sync_wid, h_total;
|
||||
|
||||
h_display = target->timing.h_display;
|
||||
h_sync_fudge = Radeon_GetHSyncFudge( si, port, format );
|
||||
h_sync_start = target->timing.h_sync_start;
|
||||
h_sync_wid = target->timing.h_sync_end - target->timing.h_sync_start;
|
||||
h_total = target->timing.h_total;
|
||||
|
||||
// make sure, display is not too small
|
||||
// (I reckon Radeon doesn't care, but your monitor probably does)
|
||||
if( h_display < 320 )
|
||||
h_display = 320;
|
||||
// apply hardware restrictions
|
||||
// as h_display is the smallest register, it's always possible
|
||||
// to adjust other values to keep them in supported range
|
||||
if( h_display > H_DISPLAY_2PIX( RADEON_CRTC_H_DISP >> RADEON_CRTC_H_DISP_SHIFT ) )
|
||||
h_display = H_DISPLAY_2PIX( RADEON_CRTC_H_DISP >> RADEON_CRTC_H_DISP_SHIFT );
|
||||
// round properly
|
||||
h_display = H_DISPLAY_2PIX( H_DISPLAY_2REG( h_display ));
|
||||
|
||||
// ensure minimum time before sync
|
||||
if( h_sync_start < h_display + 2*8 )
|
||||
h_sync_start = h_display + 2*8;
|
||||
// sync has wider range than display are, so we won't collide there,
|
||||
// but total width has same range as sync start, so leave some space
|
||||
if( h_sync_start > H_SSTART_2PIX( RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX ) - 4*8 )
|
||||
h_sync_start = H_SSTART_2PIX( RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX ) - 4*8;
|
||||
|
||||
// ensure minimum sync length
|
||||
if( h_sync_wid < H_SWID_2PIX( 3 ))
|
||||
h_sync_wid = H_SWID_2PIX( 3 );
|
||||
// allowed range is quite small, so make sure sync isn't too long
|
||||
if( h_sync_wid > H_SWID_2PIX( RADEON_CRTC_H_SYNC_WID >> RADEON_CRTC_H_SYNC_WID_SHIFT ) )
|
||||
h_sync_wid = H_SWID_2PIX( RADEON_CRTC_H_SYNC_WID >> RADEON_CRTC_H_SYNC_WID_SHIFT );
|
||||
// round properly
|
||||
h_sync_wid = H_SWID_2PIX( H_SWID_2REG( h_sync_wid ));
|
||||
|
||||
// last but not least adapt total width
|
||||
// "+7" is needed for rounding up: sync_start isn't rounded, but h_total is
|
||||
if( h_total < h_sync_start + h_sync_wid + 1*8 + 7 )
|
||||
h_total = h_sync_start + h_sync_wid + 1*8 + 7;
|
||||
// we may get a too long total width; this can only happen
|
||||
// because sync is too long, so truncate sync accordingly
|
||||
if( h_total > H_TOTAL_2PIX( RADEON_CRTC_H_TOTAL ) ) {
|
||||
h_total = H_TOTAL_2PIX( RADEON_CRTC_H_TOTAL );
|
||||
h_sync_wid = min( h_sync_wid, h_total - h_sync_start );
|
||||
h_sync_wid = H_SWID_2PIX( H_SWID_2REG( h_sync_wid ));
|
||||
}
|
||||
// round properly
|
||||
h_total = H_TOTAL_2PIX( H_TOTAL_2REG( h_total ));
|
||||
|
||||
target->timing.h_display = h_display;
|
||||
target->timing.h_sync_start = h_sync_start;
|
||||
target->timing.h_sync_end = h_sync_start + h_sync_wid;
|
||||
target->timing.h_total = h_total;
|
||||
}
|
||||
|
||||
// did we fall out of one of the limits?
|
||||
if( target->timing.h_display < low->timing.h_display ||
|
||||
target->timing.h_display > high->timing.h_display ||
|
||||
target->timing.h_sync_start < low->timing.h_sync_start ||
|
||||
target->timing.h_sync_start > high->timing.h_sync_start ||
|
||||
target->timing.h_sync_end < low->timing.h_sync_end ||
|
||||
target->timing.h_sync_end > high->timing.h_sync_end ||
|
||||
target->timing.h_total < low->timing.h_total ||
|
||||
target->timing.h_total > high->timing.h_total)
|
||||
{
|
||||
SHOW_FLOW0( 4, "out of horizontal limits" );
|
||||
result = B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// validate vertical timings
|
||||
{
|
||||
int v_display, v_sync_start, v_sync_wid, v_total;
|
||||
|
||||
v_display = target->timing.v_display;
|
||||
v_sync_start = target->timing.v_sync_start;
|
||||
v_sync_wid = target->timing.v_sync_end - target->timing.v_sync_start;
|
||||
v_total = target->timing.v_total;
|
||||
|
||||
// apply a reasonable minimal height to make monitor happy
|
||||
if( v_display < 200 )
|
||||
v_display = 200;
|
||||
// apply limits but make sure we have enough lines left for blank and sync
|
||||
if( v_display > V_2PIX(RADEON_CRTC_V_DISP >> RADEON_CRTC_V_DISP_SHIFT) - 5)
|
||||
v_display = V_2PIX(RADEON_CRTC_V_DISP >> RADEON_CRTC_V_DISP_SHIFT) - 5;
|
||||
|
||||
// leave at least one line before sync
|
||||
// (some flat panel have zero gap here; probably, this leads to
|
||||
// the infamous bright line at top of screen)
|
||||
if( v_sync_start < v_display + 1 )
|
||||
v_sync_start = v_display + 1;
|
||||
// apply hardware limit and leave some lines for sync
|
||||
if( v_sync_start > V_2PIX(RADEON_CRTC_V_SYNC_STRT) - 4)
|
||||
v_sync_start = V_2PIX(RADEON_CRTC_V_SYNC_STRT) - 4;
|
||||
|
||||
// don't make sync too short
|
||||
if( v_sync_wid < 2 )
|
||||
v_sync_wid = 2;
|
||||
// sync width is quite restricted
|
||||
if( v_sync_wid > (RADEON_CRTC_V_SYNC_WID >> RADEON_CRTC_V_SYNC_WID_SHIFT))
|
||||
v_sync_wid = (RADEON_CRTC_V_SYNC_WID >> RADEON_CRTC_V_SYNC_WID_SHIFT);
|
||||
|
||||
// leave a gap of at least 1 line
|
||||
if( v_total < v_sync_start + v_sync_wid + 1 )
|
||||
v_total = v_sync_start + v_sync_wid + 1;
|
||||
// if too long, truncate it and adapt sync len
|
||||
if( v_total > V_2PIX( RADEON_CRTC_V_TOTAL ) ) {
|
||||
v_total = V_2PIX( RADEON_CRTC_V_TOTAL );
|
||||
v_sync_wid = min( v_sync_wid, v_total - v_sync_start - 4 );
|
||||
}
|
||||
|
||||
target->timing.v_display = v_display;
|
||||
target->timing.v_sync_start = v_sync_start;
|
||||
target->timing.v_sync_end = v_sync_start + v_sync_wid;
|
||||
target->timing.v_total = v_total;
|
||||
}
|
||||
|
||||
// did we fall out of one of the limits?
|
||||
if( target->timing.v_display < low->timing.v_display ||
|
||||
target->timing.v_display > high->timing.v_display ||
|
||||
target->timing.v_sync_start < low->timing.v_sync_start ||
|
||||
target->timing.v_sync_start > high->timing.h_sync_start ||
|
||||
target->timing.v_sync_end < low->timing.v_sync_end ||
|
||||
target->timing.v_sync_end > high->timing.v_sync_end ||
|
||||
target->timing.v_total < low->timing.v_total ||
|
||||
target->timing.v_total > high->timing.v_total )
|
||||
{
|
||||
SHOW_FLOW0( 4, "out of vertical limits" );
|
||||
result = B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// restore whished refresh rate
|
||||
target->timing.pixel_clock =
|
||||
((uint64)target_refresh / 1000 * target->timing.h_total * target->timing.v_total + FIX_SCALE / 2)
|
||||
>> FIX_SHIFT;
|
||||
|
||||
// apply PLL restrictions
|
||||
if( target->timing.pixel_clock / 10 > pll->max_pll_freq ||
|
||||
target->timing.pixel_clock / 10 * 12 < pll->min_pll_freq )
|
||||
{
|
||||
SHOW_ERROR( 2, "pixel_clock (%ld) out of range (%d, %d)", target->timing.pixel_clock,
|
||||
pll->max_pll_freq * 10, pll->min_pll_freq / 12 );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// make sure virtual_size > visible_size
|
||||
// additionally, restore virtual_size == visible_size if it was so on entry
|
||||
if ((target->timing.h_display > target->virtual_width) || want_same_width)
|
||||
target->virtual_width = target->timing.h_display;
|
||||
if ((target->timing.v_display > target->virtual_height) || want_same_height)
|
||||
target->virtual_height = target->timing.v_display;
|
||||
|
||||
// TBD: limit is taken from XFree86
|
||||
// this is probably a CRTC limit; don't know about the accelerator limit (if any)
|
||||
// h_display can be at most 512*8, so we don't risk h_virtual < h_display
|
||||
// after applying this restriction
|
||||
if (target->virtual_width > 1024*8)
|
||||
target->virtual_width = 1024*8;
|
||||
|
||||
if (target->virtual_width < low->virtual_width ||
|
||||
target->virtual_width > high->virtual_width )
|
||||
{
|
||||
SHOW_FLOW0( 4, "out of virtual horizontal limits" );
|
||||
result = B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// we may have to use a larger virtual width -
|
||||
// take care of that when calculating memory consumption
|
||||
eff_virtual_width = Radeon_RoundVWidth( target->virtual_height, bpp );
|
||||
|
||||
// calculate rowbytes after we've nailed the virtual width
|
||||
row_bytes = eff_virtual_width * bpp;
|
||||
|
||||
// if we haven't enough memory, reduce virtual height
|
||||
// (some programs create back buffers by asking for a huge
|
||||
// virtual screen; they actually want to know what is possible
|
||||
// to adjust the number of back buffers according to amount
|
||||
// of graphics memory)
|
||||
|
||||
// careful about additionally required memory:
|
||||
// 1024 bytes are needed for hardware cursor
|
||||
if ((row_bytes * target->virtual_height) > si->local_mem_size - 1024 )
|
||||
target->virtual_height = (si->local_mem_size - 1024) / row_bytes;
|
||||
|
||||
// make sure we haven't shrunk virtual height too much
|
||||
if (target->virtual_height < target->timing.v_display) {
|
||||
SHOW_ERROR( 2, "not enough memory for this mode (could show only %d of %d lines)",
|
||||
target->virtual_height, target->timing.v_display );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (target->virtual_height < low->virtual_height ||
|
||||
target->virtual_height > high->virtual_height )
|
||||
{
|
||||
SHOW_FLOW0( 4, "out of virtual vertical limits" );
|
||||
result = B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// we ignore flags - in the sample driver, they did the same,
|
||||
// so why bother?
|
||||
return result;
|
||||
}
|
||||
|
||||
// public function: return number of display modes returned by get_mode_list
|
||||
uint32 ACCELERANT_MODE_COUNT( void )
|
||||
{
|
||||
return ai->si->mode_count;
|
||||
}
|
||||
|
||||
// public function: get list of standard display modes
|
||||
// dm - modes are copied to here (to be allocated by caller)
|
||||
status_t GET_MODE_LIST( display_mode *dm )
|
||||
{
|
||||
memcpy( dm, ai->mode_list, ai->si->mode_count * sizeof(display_mode) );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static const color_space spaces[4] = {
|
||||
B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE
|
||||
};
|
||||
|
||||
// if given mode is possible on this card, add it to standard mode list
|
||||
// mode - mode to add (colourspace is ignored but replaced
|
||||
// by each officially supported colour space in turn)
|
||||
// ignore_timing - don't care if timing has to be modified to make mode valid
|
||||
// (used for fp modes - we just want their resolution)
|
||||
static void checkAndAddMode( accelerator_info *ai, const display_mode *mode, bool ignore_timing )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
uint i;
|
||||
display_mode low, high;
|
||||
uint32 pix_clk_range;
|
||||
display_mode *dst;
|
||||
|
||||
if( ignore_timing ) {
|
||||
// for fp modes: don't add mode if its resolution is already in official mode list
|
||||
for( i = 0; i < si->mode_count; ++i ) {
|
||||
if( ai->mode_list[i].timing.h_display == mode->timing.h_display &&
|
||||
ai->mode_list[i].timing.v_display == mode->timing.v_display &&
|
||||
ai->mode_list[i].virtual_width == mode->virtual_width &&
|
||||
ai->mode_list[i].virtual_height == mode->virtual_height )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set ranges for acceptable values
|
||||
low = high = *mode;
|
||||
|
||||
// range is 6.25% of default clock: arbitrarily picked
|
||||
pix_clk_range = low.timing.pixel_clock >> 5;
|
||||
low.timing.pixel_clock -= pix_clk_range;
|
||||
high.timing.pixel_clock += pix_clk_range;
|
||||
|
||||
if( ignore_timing ) {
|
||||
low.timing.h_total = 0;
|
||||
low.timing.h_sync_start = 0;
|
||||
low.timing.h_sync_end = 0;
|
||||
low.timing.v_total = 0;
|
||||
low.timing.v_sync_start = 0;
|
||||
low.timing.v_sync_end = 0;
|
||||
high.timing.h_total = 0xffff;
|
||||
high.timing.h_sync_start = 0xffff;
|
||||
high.timing.h_sync_end = 0xffff;
|
||||
high.timing.v_total = 0xffff;
|
||||
high.timing.v_sync_start = 0xffff;
|
||||
high.timing.v_sync_end = 0xffff;
|
||||
}
|
||||
|
||||
dst = &ai->mode_list[si->mode_count];
|
||||
|
||||
// iterator through all colour spaces
|
||||
for( i = 0; i < (sizeof(spaces) / sizeof(color_space)); i++ ) {
|
||||
// check whether first port can handle it
|
||||
*dst = *mode;
|
||||
dst->space = low.space = high.space = spaces[i];
|
||||
|
||||
if( Radeon_ProposeDisplayMode( si, &si->ports[0],
|
||||
&si->pll, dst, &low, &high ) == B_OK )
|
||||
{
|
||||
si->mode_count++;
|
||||
++dst;
|
||||
|
||||
} else {
|
||||
// it can't, so try second port
|
||||
*dst = *mode;
|
||||
dst->space = spaces[i];
|
||||
|
||||
if( Radeon_ProposeDisplayMode( si, &si->ports[1],
|
||||
&si->pll, dst, &low, &high ) == B_OK )
|
||||
{
|
||||
si->mode_count++;
|
||||
++dst;
|
||||
|
||||
} else
|
||||
SHOW_FLOW( 4, "%ld, %ld not supported", dst->virtual_width, dst->virtual_height );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add display mode including span mode variations to offical list
|
||||
static void checkAndAddMultiMode( accelerator_info *ai, const display_mode *mode,
|
||||
bool ignore_timing )
|
||||
{
|
||||
display_mode wide_mode;
|
||||
|
||||
SHOW_FLOW( 4, "%ld, %ld", mode->virtual_width, mode->virtual_height );
|
||||
|
||||
// plain mode
|
||||
checkAndAddMode( ai, mode, ignore_timing );
|
||||
|
||||
// double width mode
|
||||
wide_mode = *mode;
|
||||
wide_mode.virtual_width *= 2;
|
||||
wide_mode.flags |= B_SCROLL;
|
||||
checkAndAddMode( ai, &wide_mode, ignore_timing );
|
||||
|
||||
// double height mode
|
||||
wide_mode = *mode;
|
||||
wide_mode.virtual_height *= 2;
|
||||
wide_mode.flags |= B_SCROLL;
|
||||
checkAndAddMode( ai, &wide_mode, ignore_timing );
|
||||
}
|
||||
|
||||
// add display mode of flat panel to official list
|
||||
static void addFPMode( accelerator_info *ai, fp_info *fp_info )
|
||||
{
|
||||
if( fp_info->disp_type == dt_dvi_1 || fp_info->disp_type == dt_lvds ) {
|
||||
display_mode mode;
|
||||
|
||||
mode.virtual_width = mode.timing.h_display = fp_info->panel_xres;
|
||||
mode.virtual_height = mode.timing.v_display = fp_info->panel_yres;
|
||||
|
||||
mode.timing.h_total = mode.timing.h_display + fp_info->h_blank;
|
||||
mode.timing.h_sync_start = mode.timing.h_display + fp_info->h_over_plus;
|
||||
mode.timing.h_sync_end = mode.timing.h_sync_start + fp_info->h_sync_width;
|
||||
mode.timing.v_total = mode.timing.v_display + fp_info->v_blank;
|
||||
mode.timing.v_sync_start = mode.timing.v_display + fp_info->v_over_plus;
|
||||
mode.timing.v_sync_end = mode.timing.v_sync_start + fp_info->v_sync_width;
|
||||
|
||||
mode.timing.pixel_clock = fp_info->dot_clock;
|
||||
|
||||
// if we have no pixel clock, assume 60 Hz
|
||||
// (as we don't program PLL in this case, it doesn't matter
|
||||
// if it's wrong, we just want this resolution in the mode list)
|
||||
if( mode.timing.pixel_clock == 0 ) {
|
||||
// devide by 1000 as clock is in kHz
|
||||
mode.timing.pixel_clock =
|
||||
((uint32)mode.timing.h_total * mode.timing.v_total * 60) / 1000;
|
||||
}
|
||||
|
||||
mode.flags = MODE_FLAGS;
|
||||
mode.h_display_start = 0;
|
||||
mode.v_display_start = 0;
|
||||
|
||||
SHOW_FLOW( 2, "H: %4d %4d %4d %4d (v=%4d)",
|
||||
mode.timing.h_display, mode.timing.h_sync_start,
|
||||
mode.timing.h_sync_end, mode.timing.h_total, mode.virtual_width );
|
||||
SHOW_FLOW( 2, "V: %4d %4d %4d %4d (h=%4d)",
|
||||
mode.timing.v_display, mode.timing.v_sync_start,
|
||||
mode.timing.v_sync_end, mode.timing.v_total, mode.virtual_height );
|
||||
SHOW_FLOW( 2, "clk: %ld", mode.timing.pixel_clock );
|
||||
|
||||
// flat panels seem to have strange timings;
|
||||
// as we ignore user-supplied timing for FPs anyway,
|
||||
// the mode can (and usually has to) be modified to be
|
||||
// used for normal CRTs
|
||||
checkAndAddMultiMode( ai, &mode, true );
|
||||
}
|
||||
}
|
||||
|
||||
// create list of officially supported modes
|
||||
status_t Radeon_CreateModeList( shared_info *si )
|
||||
{
|
||||
size_t max_size;
|
||||
uint i;
|
||||
uint max_num_modes;
|
||||
|
||||
// maximum number of official modes:
|
||||
// (predefined-modes + fp-modes) * number-of-colour-spaces * number-of-(non)-span-modes
|
||||
max_num_modes = ((sizeof( base_mode_list ) / sizeof( base_mode_list[0] ) + 1) * 4 * 3);
|
||||
|
||||
max_size = (max_num_modes * sizeof(display_mode) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
|
||||
|
||||
si->mode_list_area = create_area("Radeon accelerant mode info",
|
||||
(void **)&ai->mode_list, B_ANY_ADDRESS,
|
||||
max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||
|
||||
if( si->mode_list_area < B_OK )
|
||||
return si->mode_list_area;
|
||||
|
||||
si->mode_count = 0;
|
||||
|
||||
// check standard modes
|
||||
for( i = 0; i < sizeof( base_mode_list ) / sizeof( base_mode_list[0] ); i++ )
|
||||
checkAndAddMultiMode( ai, &base_mode_list[i], false );
|
||||
|
||||
// plus fp mode
|
||||
addFPMode( ai, &si->fp_port );
|
||||
|
||||
// as we've created the list ourself, we don't clone it
|
||||
ai->mode_list_area = si->mode_list_area;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// cleanup official display mode list
|
||||
void Radeon_DisposeModeList( shared_info *si )
|
||||
{
|
||||
delete_area( si->mode_list_area );
|
||||
}
|
||||
|
||||
|
||||
// public function: wraps for internal propose_display_mode
|
||||
status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
|
||||
const display_mode *high )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
status_t result1, result2;
|
||||
bool isTunneled;
|
||||
status_t result;
|
||||
|
||||
// check whether we got a tunneled settings command
|
||||
result = Radeon_CheckMultiMonTunnel( vc, target, low, high, &isTunneled );
|
||||
if( isTunneled )
|
||||
return result;
|
||||
|
||||
// transform to multi-screen mode first
|
||||
Radeon_DetectMultiMode( vc, target );
|
||||
Radeon_VerifyMultiMode( vc, si, target );
|
||||
|
||||
SHOW_FLOW0( 2, "wished:" );
|
||||
SHOW_FLOW( 2, "H: %4d %4d %4d %4d (v=%4d)",
|
||||
target->timing.h_display, target->timing.h_sync_start,
|
||||
target->timing.h_sync_end, target->timing.h_total, target->virtual_width );
|
||||
SHOW_FLOW( 2, "V: %4d %4d %4d %4d (h=%4d)",
|
||||
target->timing.v_display, target->timing.v_sync_start,
|
||||
target->timing.v_sync_end, target->timing.v_total, target->virtual_height );
|
||||
SHOW_FLOW( 2, "clk: %ld", target->timing.pixel_clock );
|
||||
|
||||
// we must assure that each ProposeMode call doesn't tweak the mode in
|
||||
// a way that it cannot be handled by the other port anymore
|
||||
result1 = Radeon_ProposeDisplayMode( si, &si->ports[vc->ports[0].physical_port],
|
||||
&si->pll, target, low, high );
|
||||
|
||||
if( result1 == B_ERROR )
|
||||
return B_ERROR;
|
||||
|
||||
if( Radeon_NeedsSecondPort( target )) {
|
||||
// if both ports are used, make sure both can handle mode
|
||||
result2 = Radeon_ProposeDisplayMode( si, &si->ports[vc->ports[1].physical_port],
|
||||
&si->pll, target, low, high );
|
||||
|
||||
if( result2 == B_ERROR )
|
||||
return B_ERROR;
|
||||
} else {
|
||||
result2 = B_OK;
|
||||
}
|
||||
|
||||
SHOW_INFO0( 2, "got:" );
|
||||
SHOW_INFO( 2, "H: %4d %4d %4d %4d (v=%4d)",
|
||||
target->timing.h_display, target->timing.h_sync_start,
|
||||
target->timing.h_sync_end, target->timing.h_total, target->virtual_width );
|
||||
SHOW_INFO( 2, "V: %4d %4d %4d %4d (h=%4d)",
|
||||
target->timing.v_display, target->timing.v_sync_start,
|
||||
target->timing.v_sync_end, target->timing.v_total, target->virtual_height );
|
||||
SHOW_INFO( 2, "clk: %ld", target->timing.pixel_clock );
|
||||
|
||||
Radeon_HideMultiMode( vc, target );
|
||||
|
||||
if( result1 == B_OK && result2 == B_OK )
|
||||
return B_OK;
|
||||
else
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Sets display modes, colour palette and handles DPMS
|
||||
*/
|
||||
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include "radeon_regs.h"
|
||||
#include "mmio.h"
|
||||
#include "crtc_regs.h"
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "overlay_regs.h"
|
||||
#include "capture_regs.h"
|
||||
#include "rbbm_regs.h"
|
||||
#include "dac_regs.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void Radeon_SetMode( accelerator_info *ai, virtual_port *port, display_mode *mode );
|
||||
void Radeon_EnableIRQ( accelerator_info *ai, bool enable );
|
||||
|
||||
|
||||
// Radeon's DACs share same public registers, this function
|
||||
// selects the DAC you'll talk to
|
||||
static void selectDAC( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
Radeon_WriteRegCP( ai, RADEON_DAC_CNTL2,
|
||||
(port->is_crtc2 ? RADEON_DAC2_PALETTE_ACC_CTL : 0) |
|
||||
(ai->si->dac_cntl2 & ~RADEON_DAC2_PALETTE_ACC_CTL) );
|
||||
}
|
||||
|
||||
|
||||
// set standard colour palette (needed for non-palette modes)
|
||||
static void initDAC( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
int i;
|
||||
|
||||
selectDAC( ai, port );
|
||||
|
||||
Radeon_WriteRegCP( ai, RADEON_PALETTE_INDEX, 0 );
|
||||
|
||||
for( i = 0; i < 256; ++i )
|
||||
Radeon_WriteRegCP( ai, RADEON_PALETTE_DATA, (i << 16) | (i << 8) | i );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// round virtual width up to next valid size
|
||||
uint32 Radeon_RoundVWidth( int virtual_width, int bpp )
|
||||
{
|
||||
// we have to make both the CRTC and the accelerator happy:
|
||||
// - the CRTC wants virtual width in pixels to be a multiple of 8
|
||||
// - the accelerator expects width in bytes to be a multiple of 64
|
||||
|
||||
// to put that together, width (in bytes) must be a multiple of the least
|
||||
// common nominator of bytes-per-pixel*8 (CRTC) and 64 (accelerator);
|
||||
|
||||
// if bytes-per-pixel is a power of two and less than 8, the LCM is 64;
|
||||
// almost all colour depth satisfy that apart from 24 bit; in this case,
|
||||
// the LCM is 64*3=192
|
||||
|
||||
// after dividing by bytes-per-pixel we get pixels: in first case,
|
||||
// width must be multiple of 64/bytes-per-pixel; in second case,
|
||||
// width must be multiple of 64*3/3=64
|
||||
|
||||
if( bpp != 3 )
|
||||
return (virtual_width + 64/bpp - 1) & ~(64/bpp - 1);
|
||||
else
|
||||
return (virtual_width + 63) & ~63;
|
||||
}
|
||||
|
||||
|
||||
// list of registers that must be reset before display mode switch
|
||||
// to avoid interferences
|
||||
static struct {
|
||||
uint16 reg;
|
||||
uint32 val;
|
||||
} common_regs[] = {
|
||||
{ RADEON_OVR_CLR, 0 },
|
||||
{ RADEON_OVR_WID_LEFT_RIGHT, 0 },
|
||||
{ RADEON_OVR_WID_TOP_BOTTOM, 0 },
|
||||
{ RADEON_OV0_SCALE_CNTL, 0 },
|
||||
{ RADEON_SUBPIC_CNTL, 0 },
|
||||
{ RADEON_VIPH_CONTROL, 0 },
|
||||
{ RADEON_I2C_CNTL_1, 0 },
|
||||
{ RADEON_GEN_INT_CNTL, 0 },
|
||||
{ RADEON_CAP0_TRIG_CNTL, 0 },
|
||||
};
|
||||
|
||||
static void Radeon_InitCommonRegs( accelerator_info *ai )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
uint i;
|
||||
|
||||
for( i = 0; i < sizeof( common_regs) / sizeof( common_regs[0] ); ++i )
|
||||
OUTREG( regs, common_regs[i].reg, common_regs[i].val );
|
||||
}
|
||||
|
||||
// set display mode of one port;
|
||||
// port restrictions, like fixed-sync TFTs connected to it, are taken care of
|
||||
void Radeon_SetMode( accelerator_info *ai, virtual_port *port, display_mode *mode )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
vuint8 *regs = ai->regs;
|
||||
int format;
|
||||
int bpp;
|
||||
display_type_e disp_type;
|
||||
port_regs values;
|
||||
|
||||
port->mode = *mode;
|
||||
|
||||
// don't destroy passed values, use our copy instead
|
||||
mode = &port->mode;
|
||||
|
||||
disp_type = si->ports[port->physical_port].disp_type;
|
||||
|
||||
// if using an flat panel or LCD, maximum resolution
|
||||
// is determined by the physical resolution;
|
||||
// also, all timing is fixed
|
||||
if( disp_type == dt_dvi_1 || disp_type == dt_lvds ) {
|
||||
fp_info *fp_info = &si->fp_port;
|
||||
|
||||
if( mode->timing.h_display > fp_info->panel_xres )
|
||||
mode->timing.h_display = fp_info->panel_xres;
|
||||
if( mode->timing.v_display > fp_info->panel_yres )
|
||||
mode->timing.v_display = fp_info->panel_yres;
|
||||
|
||||
mode->timing.h_total = mode->timing.h_display + fp_info->h_blank;
|
||||
mode->timing.h_sync_start = mode->timing.h_display + fp_info->h_over_plus;
|
||||
mode->timing.h_sync_end = mode->timing.h_sync_start + fp_info->h_sync_width;
|
||||
mode->timing.v_total = mode->timing.v_display + fp_info->v_blank;
|
||||
mode->timing.v_sync_start = mode->timing.v_display + fp_info->v_over_plus;
|
||||
mode->timing.v_sync_end = mode->timing.v_sync_start + fp_info->v_sync_width;
|
||||
|
||||
mode->timing.pixel_clock = fp_info->dot_clock;
|
||||
}
|
||||
|
||||
Radeon_GetFormat( mode->space, &format, &bpp );
|
||||
|
||||
vc->bpp = bpp;
|
||||
vc->datatype = format;
|
||||
|
||||
// calculate all hardware register values
|
||||
Radeon_CalcCRTCRegisters( ai, port, mode, &values );
|
||||
|
||||
values.surface_cntl = RADEON_SURF_TRANSLATION_DIS;
|
||||
|
||||
// for flat panels, we may not have pixel clock if DDC data is missing;
|
||||
// as we don't change effective resolution we can leave it as set by BIOS
|
||||
if( mode->timing.pixel_clock )
|
||||
Radeon_CalcPLLDividers( &si->pll, mode->timing.pixel_clock / 10, &values );
|
||||
|
||||
if( disp_type == dt_dvi_1 || disp_type == dt_lvds )
|
||||
Radeon_CalcFPRegisters( ai, port, &si->fp_port, mode, &values );
|
||||
|
||||
|
||||
// write values to registers
|
||||
Radeon_SetDPMS( ai, port, B_DPMS_SUSPEND );
|
||||
|
||||
Radeon_InitCommonRegs( ai );
|
||||
|
||||
Radeon_ProgramCRTCRegisters( ai, port, &values );
|
||||
|
||||
OUTREG( regs, RADEON_SURFACE_CNTL, values.surface_cntl );
|
||||
|
||||
if( disp_type == dt_dvi_1 || disp_type == dt_lvds )
|
||||
Radeon_ProgramFPRegisters( ai, &si->fp_port, &values );
|
||||
|
||||
|
||||
if( mode->timing.pixel_clock )
|
||||
Radeon_ProgramPLL( ai, port, &values );
|
||||
|
||||
Radeon_SetDPMS( ai, port, B_DPMS_ON );
|
||||
|
||||
// overlay must be setup again after modeswitch (whoever was using it)
|
||||
// TBD: this won't work if another virtual card was using it,
|
||||
// but currently, virtual cards don't work anyway...
|
||||
si->active_overlay.port = -1;
|
||||
}
|
||||
|
||||
|
||||
// enable or disable VBlank interrupts
|
||||
void Radeon_EnableIRQ( accelerator_info *ai, bool enable )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
uint32 int_cntl, int_mask;
|
||||
|
||||
int_cntl = INREG( ai->regs, RADEON_GEN_INT_CNTL );
|
||||
int_mask =
|
||||
RADEON_CRTC_VBLANK_MASK
|
||||
| (si->has_crtc2 ? RADEON_CRTC2_VBLANK_MASK : 0);
|
||||
|
||||
if( enable )
|
||||
int_cntl |= int_mask;
|
||||
else
|
||||
int_cntl &= ~int_mask;
|
||||
|
||||
OUTREG( ai->regs, RADEON_GEN_INT_CNTL, int_cntl );
|
||||
|
||||
if( enable ) {
|
||||
// on enable, we have to acknowledge all IRQs as the graphics card
|
||||
// waits for that before it issues further IRQs
|
||||
OUTREG( ai->regs, RADEON_GEN_INT_STATUS, int_cntl );
|
||||
}
|
||||
|
||||
si->enable_virtual_irq = enable;
|
||||
}
|
||||
|
||||
|
||||
// public function: set display mode
|
||||
status_t SET_DISPLAY_MODE( display_mode *mode_in )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
display_mode bounds, mode;
|
||||
|
||||
mode = bounds = *mode_in;
|
||||
|
||||
ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
SHOW_FLOW( 2, "width=%d, height=%d", mode.timing.h_display, mode.timing.v_display );
|
||||
|
||||
// check mode and tweak parameters so we can program hardware
|
||||
// without any further checks
|
||||
if( PROPOSE_DISPLAY_MODE( &mode, &bounds, &bounds ) == B_ERROR ) {
|
||||
SHOW_ERROR0( 2, "invalid mode" );
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// already done by propose_display_mode, but it was undone on return;
|
||||
// do this before equality check to recognize changed to multi-monitor mode
|
||||
Radeon_DetectMultiMode( vc, &mode );
|
||||
|
||||
// mode switches can take quite long and are visible,
|
||||
// so avoid them if possible
|
||||
if( memcmp( &mode, &vc->mode, sizeof( display_mode )) == 0 ) {
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// make sure, we don't get disturbed
|
||||
Radeon_Finish( ai );
|
||||
Radeon_EnableIRQ( ai, false );
|
||||
|
||||
// free cursor and framebuffer memory
|
||||
{
|
||||
radeon_free_local_mem fm;
|
||||
|
||||
fm.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
|
||||
if( vc->cursor.mem_handle ) {
|
||||
fm.handle = vc->cursor.mem_handle;
|
||||
ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm );
|
||||
}
|
||||
|
||||
if( vc->fb_mem_handle ) {
|
||||
fm.handle = vc->fb_mem_handle;
|
||||
ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm );
|
||||
}
|
||||
}
|
||||
|
||||
memcpy( &vc->mode, &mode, sizeof( display_mode ));
|
||||
|
||||
// verify hardware restrictions *after* saving mode
|
||||
// e.g. if you want a span mode but have one monitor disconnected,
|
||||
// configuration shouldn't be touched, so you can continue working
|
||||
// with two monitors later on just like nothing has happened
|
||||
Radeon_VerifyMultiMode( vc, si, &mode );
|
||||
|
||||
// set main flags
|
||||
vc->independant_ports = Radeon_NeedsSecondPort( &mode ) ? 2 : 1;
|
||||
vc->different_ports = Radeon_DifferentPorts( &mode );
|
||||
SHOW_FLOW( 2, "independant ports: %d", vc->independant_ports );
|
||||
vc->scroll = mode.flags & B_SCROLL;
|
||||
SHOW_FLOW( 2, "scrolling %s", vc->scroll ? "enabled" : "disabled" );
|
||||
|
||||
// allocate frame buffer and cursor image memory
|
||||
{
|
||||
radeon_alloc_local_mem am;
|
||||
int format, bpp;
|
||||
|
||||
// alloc cursor memory
|
||||
am.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
am.size = 1024;
|
||||
|
||||
if( ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am ) == B_OK ) {
|
||||
vc->cursor.mem_handle = am.handle;
|
||||
vc->cursor.fb_offset = am.fb_offset;
|
||||
} else {
|
||||
// too bad that we are out of mem -> set reasonable values as
|
||||
// it's too late to give up (ouch!)
|
||||
SHOW_ERROR0( 2, "no memory for cursor image!" );
|
||||
vc->cursor.mem_handle = 0;
|
||||
vc->cursor.fb_offset = 0;
|
||||
}
|
||||
|
||||
vc->cursor.data = si->framebuffer + vc->cursor.fb_offset;
|
||||
|
||||
// alloc frame buffer
|
||||
Radeon_GetFormat( mode.space, &format, &bpp );
|
||||
vc->pitch = Radeon_RoundVWidth( mode.virtual_width, bpp ) * bpp;
|
||||
am.size = vc->pitch * mode.virtual_height;
|
||||
|
||||
if( ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am ) == B_OK ) {
|
||||
vc->fb_mem_handle = am.handle;
|
||||
vc->fb_offset = am.fb_offset;
|
||||
} else {
|
||||
// ouch again - set reasonable values
|
||||
SHOW_ERROR0( 2, "no memory for frame buffer!" );
|
||||
vc->fb_mem_handle = 0;
|
||||
vc->fb_offset = 1024;
|
||||
}
|
||||
|
||||
vc->fbc.frame_buffer = si->framebuffer + vc->fb_offset;
|
||||
vc->fbc.frame_buffer_dma = (void *)((uint8 *)si->framebuffer_pci + vc->fb_offset);
|
||||
vc->fbc.bytes_per_row = vc->pitch;
|
||||
}
|
||||
|
||||
// multi-screen stuff
|
||||
Radeon_InitMultiModeVars( vc, &mode );
|
||||
|
||||
// GO!
|
||||
Radeon_SetMode( ai, &vc->ports[0], &mode );
|
||||
|
||||
if( vc->independant_ports > 1 )
|
||||
Radeon_SetMode( ai, &vc->ports[1], &mode );
|
||||
|
||||
SHOW_FLOW( 3, "pitch=%ld", vc->pitch );
|
||||
|
||||
// we'll modify bits of this reg, so save it for async access
|
||||
si->dac_cntl2 = INREG( ai->regs, RADEON_DAC_CNTL2 );
|
||||
|
||||
// init accelerator
|
||||
Radeon_Init2D( ai, vc->datatype );
|
||||
|
||||
// remember that 2D accelerator is not prepared for any virtual card
|
||||
si->active_vc = -1;
|
||||
|
||||
Radeon_ActivateVirtualCard( ai );
|
||||
|
||||
// first move to well-defined position (to setup CRTC offset)
|
||||
Radeon_MoveDisplay( ai, 0, 0 );
|
||||
// then to (probably faulty) user-defined pos
|
||||
Radeon_MoveDisplay( ai, mode.h_display_start, mode.v_display_start );
|
||||
|
||||
// set standard palette in direct-colour modes
|
||||
initDAC( ai, &vc->ports[0] );
|
||||
if( vc->independant_ports > 1 )
|
||||
initDAC( ai, &vc->ports[1] );
|
||||
|
||||
// initialize cursor data
|
||||
Radeon_SetCursorColors( ai, &vc->ports[0] );
|
||||
if( vc->independant_ports > 1 )
|
||||
Radeon_SetCursorColors( ai, &vc->ports[1] );
|
||||
|
||||
// sync should be settled now, so we can reenable IRQs
|
||||
// TBD: IRQ handling doesn't work correctly and doesn't make sense with two
|
||||
// displays connected, so let's leave them disabled for now
|
||||
//Radeon_EnableIRQ( ai, true );
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
|
||||
// !! all this must be done after lock has been
|
||||
// released to avoid dead-lock !!
|
||||
// TBD: any invalid intermediate states?
|
||||
|
||||
// move_cursor sets all cursor-related variables and registers
|
||||
vc->cursor.is_visible = false;
|
||||
MOVE_CURSOR( 0, 0 );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// update shown are of one port
|
||||
static void moveOneDisplay( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
uint32 offset;
|
||||
|
||||
offset = (vc->mode.v_display_start + port->rel_y) * vc->pitch +
|
||||
(vc->mode.h_display_start + port->rel_x) * vc->bpp +
|
||||
vc->fb_offset;
|
||||
|
||||
SHOW_FLOW( 3, "Setting address %x on port %d",
|
||||
offset, port->is_crtc2 );
|
||||
|
||||
Radeon_WaitForFifo( ai, 1 );
|
||||
|
||||
OUTREG( ai->regs, port->is_crtc2 ? RADEON_CRTC2_OFFSET : RADEON_CRTC_OFFSET, offset );
|
||||
/* Radeon_WriteRegCP( ai, port->is_crtc2 ? RADEON_CRTC2_OFFSET : RADEON_CRTC_OFFSET,
|
||||
offset );*/
|
||||
}
|
||||
|
||||
status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
|
||||
SHOW_FLOW( 4, "h_display_start=%ld, v_display_start=%ld",
|
||||
h_display_start, v_display_start );
|
||||
|
||||
if( h_display_start + vc->eff_width > vc->mode.virtual_width ||
|
||||
v_display_start + vc->eff_height > vc->mode.virtual_height )
|
||||
return B_ERROR;
|
||||
|
||||
// this is needed both for get_mode_info and for scrolling of virtual screens
|
||||
vc->mode.h_display_start = h_display_start & ~7;
|
||||
vc->mode.v_display_start = v_display_start;
|
||||
|
||||
// do it
|
||||
moveOneDisplay( ai, &vc->ports[0] );
|
||||
|
||||
if( vc->independant_ports > 1 )
|
||||
moveOneDisplay( ai, &vc->ports[1] );
|
||||
|
||||
// overlay position must be adjusted
|
||||
Radeon_UpdateOverlay( ai );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// public function: pan display
|
||||
status_t MOVE_DISPLAY( uint16 h_display_start, uint16 v_display_start )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
status_t result;
|
||||
|
||||
ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
// TBD: we should probably lock card first; in this case, we must
|
||||
// split this function into locking and worker part, as this
|
||||
// function is used internally as well
|
||||
result = Radeon_MoveDisplay( ai, h_display_start, v_display_start );
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void setPalette( accelerator_info *ai, virtual_port *port,
|
||||
uint count, uint8 first, uint8 *color_data );
|
||||
|
||||
// public function: set colour palette
|
||||
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
// uint i;
|
||||
|
||||
SHOW_FLOW( 3, "first=%d, count=%d", first, flags );
|
||||
|
||||
if( vc->mode.space != B_CMAP8 ) {
|
||||
SHOW_ERROR0( 2, "Tried to set palette in non-palette mode" );
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to lock card, though this isn't done in sample driver
|
||||
ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
setPalette( ai, &vc->ports[0], count, first, color_data );
|
||||
|
||||
if( vc->independant_ports > 1 )
|
||||
setPalette( ai, &vc->ports[1], count, first, color_data );
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
}
|
||||
|
||||
|
||||
// set palette of one DAC
|
||||
static void setPalette( accelerator_info *ai, virtual_port *port,
|
||||
uint count, uint8 first, uint8 *color_data )
|
||||
{
|
||||
uint i;
|
||||
|
||||
selectDAC( ai, port );
|
||||
|
||||
Radeon_WriteRegCP( ai, RADEON_PALETTE_INDEX, first );
|
||||
|
||||
for( i = 0; i < count; ++i, color_data += 3 )
|
||||
Radeon_WriteRegCP( ai, RADEON_PALETTE_DATA,
|
||||
((uint32)color_data[0] << 16) |
|
||||
((uint32)color_data[1] << 8) |
|
||||
color_data[2] );
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
CRTC programming
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
//#include "../include/radeon_regs.h"
|
||||
#include "mmio.h"
|
||||
#include "crtc_regs.h"
|
||||
#include "dac_regs.h"
|
||||
|
||||
// hammer CRTC registers
|
||||
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, virtual_port *port,
|
||||
port_regs *values )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
|
||||
SHOW_FLOW0( 2, "" );
|
||||
|
||||
if( port->is_crtc2 ) {
|
||||
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc_gen_cntl,
|
||||
RADEON_CRTC2_VSYNC_DIS |
|
||||
RADEON_CRTC2_HSYNC_DIS |
|
||||
RADEON_CRTC2_DISP_DIS );
|
||||
|
||||
switch( ai->si->asic ) {
|
||||
case rt_r200:
|
||||
case rt_r300:
|
||||
OUTREG( regs, RADEON_DISP_OUTPUT_CNTL, values->disp_output_cntl );
|
||||
break;
|
||||
default:
|
||||
OUTREG( regs, RADEON_DAC_CNTL2, values->dac_cntl );
|
||||
}
|
||||
|
||||
OUTREG( regs, RADEON_CRTC2_H_TOTAL_DISP, values->crtc_h_total_disp );
|
||||
OUTREG( regs, RADEON_CRTC2_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid );
|
||||
OUTREG( regs, RADEON_CRTC2_V_TOTAL_DISP, values->crtc_v_total_disp );
|
||||
OUTREG( regs, RADEON_CRTC2_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid );
|
||||
OUTREG( regs, RADEON_CRTC2_OFFSET_CNTL, values->crtc_offset_cntl );
|
||||
OUTREG( regs, RADEON_CRTC2_PITCH, values->crtc_pitch );
|
||||
|
||||
} else {
|
||||
OUTREG( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl );
|
||||
|
||||
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl,
|
||||
RADEON_CRTC_VSYNC_DIS |
|
||||
RADEON_CRTC_HSYNC_DIS |
|
||||
RADEON_CRTC_DISPLAY_DIS );
|
||||
|
||||
OUTREGP( regs, RADEON_DAC_CNTL, values->dac_cntl,
|
||||
RADEON_DAC_RANGE_CNTL | RADEON_DAC_BLANKING );
|
||||
|
||||
OUTREG( regs, RADEON_CRTC_H_TOTAL_DISP, values->crtc_h_total_disp );
|
||||
OUTREG( regs, RADEON_CRTC_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid );
|
||||
OUTREG( regs, RADEON_CRTC_V_TOTAL_DISP, values->crtc_v_total_disp );
|
||||
OUTREG( regs, RADEON_CRTC_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid );
|
||||
OUTREG( regs, RADEON_CRTC_OFFSET_CNTL, values->crtc_offset_cntl );
|
||||
OUTREG( regs, RADEON_CRTC_PITCH, values->crtc_pitch );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get required hsync delay depending on bit depth and output device
|
||||
uint16 Radeon_GetHSyncFudge( shared_info *si, physical_port *port, int datatype )
|
||||
{
|
||||
static int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
|
||||
static int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 };
|
||||
|
||||
// there is an sync delay which depends on colour-depth and output device
|
||||
if( port->disp_type == dt_dvi_1 || port->disp_type == dt_dvi_2 ||
|
||||
port->disp_type == dt_lvds )
|
||||
return hsync_fudge_fp[datatype - 1];
|
||||
else
|
||||
return hsync_fudge_default[datatype - 1];
|
||||
}
|
||||
|
||||
|
||||
// calculate CRTC register content
|
||||
void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
|
||||
display_mode *mode, port_regs *values )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
int hsync_start;
|
||||
int hsync_wid;
|
||||
int hsync_fudge;
|
||||
int vsync_wid;
|
||||
display_type_e disp_type;
|
||||
physical_port *phys_port = &si->ports[port->physical_port];
|
||||
|
||||
disp_type = si->ports[port->physical_port].disp_type;
|
||||
hsync_fudge = Radeon_GetHSyncFudge( si, phys_port, vc->datatype );
|
||||
|
||||
if( port->is_crtc2 ) {
|
||||
values->crtc_gen_cntl = (RADEON_CRTC2_EN
|
||||
| RADEON_CRTC2_CRT2_ON
|
||||
| (vc->datatype << 8)
|
||||
| (0/*doublescan*/ ? RADEON_CRTC2_DBL_SCAN_EN : 0)
|
||||
| ((mode->timing.flags & B_TIMING_INTERLACED)
|
||||
? RADEON_CRTC2_INTERLACE_EN : 0));
|
||||
|
||||
//values->crtc_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
|
||||
|
||||
// make ports independant of each other
|
||||
switch( si->asic ) {
|
||||
case rt_r200:
|
||||
case rt_r300:
|
||||
values->disp_output_cntl = INREG( ai->regs, RADEON_DISP_OUTPUT_CNTL );
|
||||
values->disp_output_cntl =
|
||||
(values->disp_output_cntl & ~RADEON_DISP_DAC_SOURCE_MASK)
|
||||
| RADEON_DISP_DAC_SOURCE_CRTC2;
|
||||
break;
|
||||
default:
|
||||
// we always use CRTC1 for FP and CRTC2 for CRT
|
||||
// a better way were to take output device into consideration too
|
||||
values->dac_cntl = INREG( ai->regs, RADEON_DAC_CNTL2 ) &
|
||||
~RADEON_DAC_CLK_SEL;
|
||||
values->dac_cntl |= RADEON_DAC_CLK_SEL_CRTC2;
|
||||
}
|
||||
|
||||
} else {
|
||||
// here, we should set interlace/double scan mode
|
||||
// but we don't support them (anyone missing them?)
|
||||
values->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN
|
||||
| RADEON_CRTC_EN
|
||||
| (vc->datatype << 8));
|
||||
|
||||
// we shouldn't set CRT_ON if a flat panel is connected,
|
||||
// but this flag seems to be independant of CRTC the
|
||||
// CRT is connected to
|
||||
values->crtc_ext_cntl =
|
||||
RADEON_VGA_ATI_LINEAR |
|
||||
RADEON_XCRT_CNT_EN |
|
||||
RADEON_CRTC_CRT_ON;
|
||||
|
||||
values->dac_cntl = RADEON_DAC_MASK_ALL
|
||||
| RADEON_DAC_VGA_ADR_EN
|
||||
| RADEON_DAC_8BIT_EN;
|
||||
}
|
||||
|
||||
values->crtc_h_total_disp =
|
||||
((mode->timing.h_total / 8 - 1) & RADEON_CRTC_H_TOTAL)
|
||||
| (((mode->timing.h_display / 8 - 1) << RADEON_CRTC_H_DISP_SHIFT) & RADEON_CRTC_H_DISP);
|
||||
|
||||
hsync_wid = (mode->timing.h_sync_end - mode->timing.h_sync_start) / 8;
|
||||
|
||||
hsync_start = mode->timing.h_sync_start - 8 + hsync_fudge;
|
||||
|
||||
// TBD: the sync may be the other way around
|
||||
values->crtc_h_sync_strt_wid =
|
||||
(hsync_start & (RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX))
|
||||
| (hsync_wid << RADEON_CRTC_H_SYNC_WID_SHIFT)
|
||||
| ((mode->flags & B_POSITIVE_HSYNC) == 0 ? RADEON_CRTC_H_SYNC_POL : 0);
|
||||
|
||||
values->crtc_v_total_disp =
|
||||
((mode->timing.v_total - 1) & RADEON_CRTC_V_TOTAL)
|
||||
| (((mode->timing.v_display - 1) << RADEON_CRTC_V_DISP_SHIFT) & RADEON_CRTC_V_DISP);
|
||||
|
||||
vsync_wid = mode->timing.v_sync_end - mode->timing.v_sync_start;
|
||||
|
||||
// TBD: vertial sync may be the other way around
|
||||
values->crtc_v_sync_strt_wid =
|
||||
((mode->timing.v_sync_start - 1) & RADEON_CRTC_V_SYNC_STRT)
|
||||
| (vsync_wid << RADEON_CRTC_V_SYNC_WID_SHIFT)
|
||||
| ((mode->flags & B_POSITIVE_VSYNC) == 0
|
||||
? RADEON_CRTC_V_SYNC_POL : 0);
|
||||
|
||||
values->crtc_offset_cntl = 0;
|
||||
|
||||
values->crtc_pitch = Radeon_RoundVWidth( mode->virtual_width, vc->bpp ) / 8;
|
||||
|
||||
SHOW_FLOW( 2, "crtc_pitch=%ld", values->crtc_pitch );
|
||||
|
||||
values->crtc_pitch |= values->crtc_pitch << 16;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
Main DDC communication
|
||||
*/
|
||||
|
||||
#include <OS.h>
|
||||
#include <KernelExport.h>
|
||||
#include <stdlib.h>
|
||||
#include "ddc_int.h"
|
||||
#include "edid.h"
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define READ_RETRIES 4
|
||||
|
||||
status_t ddc2_read_edid1( const i2c_bus *bus, edid1_info *edid, void **vdif, size_t *vdif_len );
|
||||
|
||||
// verify checksum of ddc data
|
||||
// (some monitors have a broken checksum - bad luck for them)
|
||||
static status_t verify_checksum( const uint8 *data, size_t len )
|
||||
{
|
||||
int i;
|
||||
uint8 sum = 0;
|
||||
uint8 all_or = 0;
|
||||
|
||||
for( i = 0; i < (int)len; ++i, ++data ) {
|
||||
sum += *data;
|
||||
all_or |= *data;
|
||||
// SHOW_FLOW( 2, "%x", *data );
|
||||
}
|
||||
|
||||
if( all_or == 0 ) {
|
||||
SHOW_INFO0( 2, "DDC information contains zeros only" );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// SHOW_INFO( 2, "sum=%x", sum );
|
||||
|
||||
if( sum != 0 ) {
|
||||
SHOW_INFO0( 2, "Checksum error of DDC information" );
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// read ddc2 data from monitor
|
||||
static status_t ddc2_read( const i2c_bus *bus, int start, uint8 *buffer, size_t len )
|
||||
{
|
||||
uint8 write_buffer[2];
|
||||
i2c_timing timing;
|
||||
int i;
|
||||
status_t res = B_ERROR;
|
||||
|
||||
write_buffer[0] = start & 0xff;
|
||||
write_buffer[1] = (start >> 8) & 0xff;
|
||||
|
||||
i2c_get100k_timing( &timing );
|
||||
|
||||
timing.start_timeout = 550;
|
||||
timing.byte_timeout = 2200;
|
||||
timing.bit_timeout = 40;
|
||||
timing.ack_start_timeout = 40;
|
||||
timing.ack_timeout = 40;
|
||||
|
||||
for( i = 0; i < READ_RETRIES; ++i ) {
|
||||
res = i2c_send_receive( bus, &timing,
|
||||
0xa0, write_buffer, start < 0x100 ? 1 : 2,
|
||||
buffer, len );
|
||||
if( res == B_OK && verify_checksum( buffer, len ) == B_OK )
|
||||
break;
|
||||
|
||||
res = B_ERROR;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// reading VDIF has not been tested.
|
||||
// it seems that almost noone supports VDIF which makes testing hard,
|
||||
// but what's the point anyway?
|
||||
#if 0
|
||||
static status_t ddc2_read_vdif( const i2c_bus *bus, int start,
|
||||
void **vdif, size_t *vdif_len )
|
||||
{
|
||||
status_t res;
|
||||
uint8 *data, *cur_data;
|
||||
int i;
|
||||
uint8 buffer[64];
|
||||
|
||||
*vdif = NULL;
|
||||
*vdif_len = 0;
|
||||
|
||||
res = ddc2_read( bus, start, buffer, 64 );
|
||||
SHOW_INFO( 2, "%x", buffer[0] );
|
||||
if( res != B_OK || buffer[0] == 0 )
|
||||
return B_OK;
|
||||
|
||||
// each block is 63 bytes plus 1 checksum long
|
||||
// we strip the checksum but store data directly into
|
||||
// buffer, so we need an extra byte for checksum of the last block
|
||||
data = malloc( buffer[0] * 63 + 1 );
|
||||
if( data == NULL )
|
||||
return B_NO_MEMORY;
|
||||
|
||||
cur_data = data;
|
||||
for( i = 0; i < buffer[0]; ++i ) {
|
||||
ddc2_read( bus, start + i * 64, cur_data, 64 );
|
||||
// strip checksum byte
|
||||
cur_data += 63;
|
||||
}
|
||||
|
||||
*vdif_len = buffer[0] * 63;
|
||||
*vdif = data;
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
// read EDID and VDIF from monitor via ddc2
|
||||
status_t ddc2_read_edid1( const i2c_bus *bus, edid1_info *edid,
|
||||
void **vdif, size_t *vdif_len )
|
||||
{
|
||||
status_t res;
|
||||
edid1_raw raw;
|
||||
|
||||
// see edid_raw.h for values to be expected
|
||||
SHOW_INFO( 5, "structure size test: %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld",
|
||||
sizeof( edid1_header_raw ),
|
||||
sizeof( edid1_vendor_raw ),
|
||||
sizeof( edid1_version_raw ),
|
||||
sizeof( edid1_display_raw ),
|
||||
sizeof( edid1_established_timing ),
|
||||
sizeof( edid1_std_timing_raw ),
|
||||
sizeof( edid1_detailed_monitor_raw ),
|
||||
sizeof( edid1_raw ));
|
||||
|
||||
res = ddc2_read( bus, 0, (uint8 *)&raw, sizeof( raw ));
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
edid_decode( edid, &raw );
|
||||
|
||||
*vdif = NULL;
|
||||
*vdif_len = 0;
|
||||
|
||||
// skip vdif as long as it's not tested
|
||||
#if 0
|
||||
res = ddc2_read_vdif( bus, sizeof( raw ) * (edid->num_sections + 1),
|
||||
vdif, vdif_len );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
#endif
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
Main DDC communication
|
||||
*/
|
||||
|
||||
#ifndef _DDC_H
|
||||
#define _DDC_H
|
||||
|
||||
#include "i2c.h"
|
||||
#include "edid.h"
|
||||
|
||||
// read EDID and VDIF from monitor via ddc2
|
||||
// (currently, *vdif and *vdif_len is always set to null)
|
||||
status_t ddc2_read_edid1( const i2c_bus *bus, edid1_info *edid,
|
||||
void **vdif, size_t *vdif_len );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
Internal header
|
||||
*/
|
||||
|
||||
// no dprintf in user space, but if you know the trick ;)
|
||||
void _kdprintf_(const char *format, ...);
|
||||
//bool set_dprintf_enabled(bool); /* returns old enable flag */
|
||||
|
||||
#define dprintf _kdprintf_
|
||||
|
||||
// don't use variables here as this is a static library
|
||||
// and thus the variables will collide with the main program
|
||||
#define debug_level_flow 2
|
||||
#define debug_level_info 4
|
||||
#define debug_level_error 4
|
||||
#define DEBUG_MSG_PREFIX "DDC "
|
||||
|
||||
#include "debug_ext.h"
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Display Power Management (DPMS) support
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "mmio.h"
|
||||
#include "crtc_regs.h"
|
||||
#include "fp_regs.h"
|
||||
#include "GlobalData.h"
|
||||
|
||||
// these static functions are moved to end of file to
|
||||
// make sure gcc doesn't inline them - we prefer size and not
|
||||
// speed for this file
|
||||
static status_t Radeon_SetDPMS_CRTC1( accelerator_info *di, int mode );
|
||||
static status_t Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode );
|
||||
static uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di );
|
||||
static uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di );
|
||||
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags);
|
||||
uint32 DPMS_CAPABILITIES(void);
|
||||
uint32 DPMS_MODE(void);
|
||||
|
||||
|
||||
// public function: set DPMS mode
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
status_t result1, result2;
|
||||
|
||||
result1 = Radeon_SetDPMS( ai, &vc->ports[0], dpms_flags );
|
||||
|
||||
if( vc->independant_ports > 1 )
|
||||
result2 = Radeon_SetDPMS( ai, &vc->ports[1], dpms_flags );
|
||||
else
|
||||
result2 = B_OK;
|
||||
|
||||
if( result1 == B_OK && result2 == B_OK )
|
||||
return B_OK;
|
||||
else
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// public function: report DPMS capabilities
|
||||
uint32 DPMS_CAPABILITIES(void)
|
||||
{
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
// public function: get current DPMS mode
|
||||
uint32 DPMS_MODE(void)
|
||||
{
|
||||
// we just ask the primary port what status it is in
|
||||
return Radeon_GetDPMS( ai, &ai->vc->ports[0] );
|
||||
}
|
||||
|
||||
|
||||
// set DPMS mode of one port
|
||||
status_t Radeon_SetDPMS( accelerator_info *ai, virtual_port *port, int mode )
|
||||
{
|
||||
// if we have a laptop panel
|
||||
// and we have a second screen connected
|
||||
// and they both show the same content,
|
||||
// then switch the laptop display always off
|
||||
if( ai->si->ports[port->physical_port].disp_type == dt_lvds &&
|
||||
ai->vc->independant_ports > 1 &&
|
||||
ai->vc->different_ports == 1 )
|
||||
{
|
||||
mode = B_DPMS_OFF;
|
||||
}
|
||||
|
||||
if( port->is_crtc2 )
|
||||
return Radeon_SetDPMS_CRTC2( ai, mode );
|
||||
else
|
||||
return Radeon_SetDPMS_CRTC1( ai, mode );
|
||||
}
|
||||
|
||||
|
||||
// get DPMS mode of one port
|
||||
uint32 Radeon_GetDPMS( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
if( port->is_crtc2 )
|
||||
return Radeon_GetDPMS_CRTC2( ai );
|
||||
else
|
||||
return Radeon_GetDPMS_CRTC1( ai );
|
||||
}
|
||||
|
||||
|
||||
// set DPMS mode for first port
|
||||
status_t Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
shared_info *si = ai->si;
|
||||
|
||||
int mask = RADEON_CRTC_DISPLAY_DIS
|
||||
| RADEON_CRTC_HSYNC_DIS
|
||||
| RADEON_CRTC_VSYNC_DIS;
|
||||
|
||||
switch( mode ) {
|
||||
case B_DPMS_ON:
|
||||
/* Screen: On; HSync: On, VSync: On */
|
||||
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~mask );
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
/* Screen: Off; HSync: Off, VSync: On */
|
||||
OUTREGP( regs, RADEON_CRTC_EXT_CNTL,
|
||||
RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS, ~mask );
|
||||
break;
|
||||
case B_DPMS_SUSPEND:
|
||||
/* Screen: Off; HSync: On, VSync: Off */
|
||||
OUTREGP( regs, RADEON_CRTC_EXT_CNTL,
|
||||
RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS, ~mask );
|
||||
break;
|
||||
case B_DPMS_OFF:
|
||||
/* Screen: Off; HSync: Off, VSync: Off */
|
||||
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, mask, ~mask );
|
||||
break;
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// if this is a flat panel, switch off backlight too
|
||||
if( si->ports[0].disp_type == dt_dvi_1 || si->ports[0].disp_type == dt_lvds ) {
|
||||
switch( mode ) {
|
||||
case B_DPMS_ON:
|
||||
// on my laptop, the display has problems to wake-up, this
|
||||
// should hopefully cure that
|
||||
// (you get a dark picture first that becomes brighter step by step,
|
||||
// after a couple of seconds you have full brightness again)
|
||||
OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON );
|
||||
//snooze( ai->si->fp_port.panel_pwr_delay * 1000 );
|
||||
OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON | RADEON_LVDS_ON,
|
||||
~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) );
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
case B_DPMS_SUSPEND:
|
||||
case B_DPMS_OFF:
|
||||
OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_DISPLAY_DIS,
|
||||
~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// it seems that DPMS doesn't work on DVI, so we disable FP completely
|
||||
// (according to specs this is the official way to handle DVI though DPMS
|
||||
// *should* be supported as well)
|
||||
if( si->ports[0].disp_type == dt_dvi_1 ) {
|
||||
switch( mode ) {
|
||||
case B_DPMS_ON:
|
||||
OUTREGP( regs, RADEON_FP_GEN_CNTL, RADEON_FP_FPON, ~RADEON_FP_FPON );
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
case B_DPMS_SUSPEND:
|
||||
case B_DPMS_OFF:
|
||||
OUTREGP( regs, RADEON_FP_GEN_CNTL, 0, ~RADEON_FP_FPON );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// set DPMS mode of second port
|
||||
status_t Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode )
|
||||
{
|
||||
vuint8 *regs = di->regs;
|
||||
|
||||
int mask = RADEON_CRTC2_DISP_DIS
|
||||
| RADEON_CRTC2_HSYNC_DIS
|
||||
| RADEON_CRTC2_VSYNC_DIS;
|
||||
|
||||
switch( mode ) {
|
||||
case B_DPMS_ON:
|
||||
/* Screen: On; HSync: On, VSync: On */
|
||||
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~mask );
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
/* Screen: Off; HSync: Off, VSync: On */
|
||||
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL,
|
||||
RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, ~mask );
|
||||
break;
|
||||
case B_DPMS_SUSPEND:
|
||||
/* Screen: Off; HSync: On, VSync: Off */
|
||||
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL,
|
||||
RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, ~mask );
|
||||
break;
|
||||
case B_DPMS_OFF:
|
||||
/* Screen: Off; HSync: Off, VSync: Off */
|
||||
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, mask, ~mask );
|
||||
break;
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// get DPMS mode of first port
|
||||
uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di )
|
||||
{
|
||||
uint32 tmp;
|
||||
|
||||
tmp = INREG( di->regs, RADEON_CRTC_EXT_CNTL );
|
||||
|
||||
if( (tmp & RADEON_CRTC_DISPLAY_DIS) == 0 )
|
||||
return B_DPMS_ON;
|
||||
|
||||
if( (tmp & RADEON_CRTC_VSYNC_DIS) == 0 )
|
||||
return B_DPMS_STAND_BY;
|
||||
|
||||
if( (tmp & RADEON_CRTC_HSYNC_DIS) == 0 )
|
||||
return B_DPMS_SUSPEND;
|
||||
|
||||
return B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
// get DPMS mode of second port
|
||||
uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di )
|
||||
{
|
||||
uint32 tmp;
|
||||
|
||||
tmp = INREG( di->regs, RADEON_CRTC2_GEN_CNTL );
|
||||
|
||||
if( (tmp & RADEON_CRTC2_DISP_DIS) == 0 )
|
||||
return B_DPMS_ON;
|
||||
|
||||
if( (tmp & RADEON_CRTC2_VSYNC_DIS) == 0 )
|
||||
return B_DPMS_STAND_BY;
|
||||
|
||||
if( (tmp & RADEON_CRTC2_HSYNC_DIS) == 0 )
|
||||
return B_DPMS_SUSPEND;
|
||||
|
||||
return B_DPMS_OFF;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
Dumps EDID content
|
||||
*/
|
||||
|
||||
#include "edid.h"
|
||||
#include <KernelExport.h>
|
||||
#include "ddc_int.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void edid_dump( edid1_info *edid )
|
||||
{
|
||||
int i, j;
|
||||
char buffer[256];
|
||||
|
||||
SHOW_INFO( 0, "Vendor: %s", edid->vendor.manufacturer );
|
||||
SHOW_INFO( 0, "Product ID: %d", (int)edid->vendor.prod_id );
|
||||
SHOW_INFO( 0, "Serial #: %d", (int)edid->vendor.serial );
|
||||
SHOW_INFO( 0, "Produced in week/year: %d/%d", edid->vendor.week, edid->vendor.year );
|
||||
|
||||
SHOW_INFO( 0, "EDID version: %d.%d", edid->version.version, edid->version.revision );
|
||||
|
||||
SHOW_INFO( 0, "Type: %s", edid->display.input_type ? "Digital" : "Analog" );
|
||||
SHOW_INFO( 0, "Size: %d cm x %d cm", edid->display.h_size, edid->display.v_size );
|
||||
SHOW_INFO( 0, "Gamma=%.3f", (edid->display.gamma + 100) / 100.0 );
|
||||
SHOW_INFO( 0, "White (X,Y)=(%.3f,%.3f)", edid->display.white_x / 1024.0, edid->display.white_y / 1024.0 );
|
||||
|
||||
SHOW_INFO0( 0, "Supported Future Video Modes:" );
|
||||
for( i = 0; i < EDID1_NUM_STD_TIMING; ++i ) {
|
||||
if( edid->std_timing[i].h_size <= 256 )
|
||||
continue;
|
||||
|
||||
SHOW_INFO( 0, "%dx%d@%dHz (id=%d)",
|
||||
edid->std_timing[i].h_size, edid->std_timing[i].v_size,
|
||||
edid->std_timing[i].refresh, edid->std_timing[i].id );
|
||||
}
|
||||
|
||||
SHOW_INFO0( 0, "Supported VESA Video Modes:" );
|
||||
if( edid->established_timing.res_720x400x70 )
|
||||
SHOW_INFO0( 0, "720x400@70" );
|
||||
if( edid->established_timing.res_720x400x88 )
|
||||
SHOW_INFO0( 0, "720x400@88" );
|
||||
if( edid->established_timing.res_640x480x60 )
|
||||
SHOW_INFO0( 0, "640x480@60" );
|
||||
if( edid->established_timing.res_640x480x67 )
|
||||
SHOW_INFO0( 0, "640x480x67" );
|
||||
if( edid->established_timing.res_640x480x72 )
|
||||
SHOW_INFO0( 0, "640x480x72" );
|
||||
if( edid->established_timing.res_640x480x75 )
|
||||
SHOW_INFO0( 0, "640x480x75" );
|
||||
if( edid->established_timing.res_800x600x56 )
|
||||
SHOW_INFO0( 0, "800x600@56" );
|
||||
if( edid->established_timing.res_800x600x60 )
|
||||
SHOW_INFO0( 0, "800x600@60" );
|
||||
|
||||
if( edid->established_timing.res_800x600x72 )
|
||||
SHOW_INFO0( 0, "800x600@72" );
|
||||
if( edid->established_timing.res_800x600x75 )
|
||||
SHOW_INFO0( 0, "800x600@75" );
|
||||
if( edid->established_timing.res_832x624x75 )
|
||||
SHOW_INFO0( 0, "832x624@75" );
|
||||
if( edid->established_timing.res_1024x768x87i )
|
||||
SHOW_INFO0( 0, "1024x768@87 interlaced" );
|
||||
if( edid->established_timing.res_1024x768x60 )
|
||||
SHOW_INFO0( 0, "1024x768@60" );
|
||||
if( edid->established_timing.res_1024x768x70 )
|
||||
SHOW_INFO0( 0, "1024x768@70" );
|
||||
if( edid->established_timing.res_1024x768x75 )
|
||||
SHOW_INFO0( 0, "1024x768@75" );
|
||||
if( edid->established_timing.res_1280x1024x75 )
|
||||
SHOW_INFO0( 0, "1280x1024@75" );
|
||||
|
||||
if( edid->established_timing.res_1152x870x75 )
|
||||
SHOW_INFO0( 0, "1152x870@75" );
|
||||
|
||||
for( i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i ) {
|
||||
edid1_detailed_monitor *monitor = &edid->detailed_monitor[i];
|
||||
|
||||
switch( monitor->monitor_desc_type ) {
|
||||
case edid1_serial_number:
|
||||
SHOW_INFO( 0, "Serial Number: %s", monitor->data.serial_number );
|
||||
break;
|
||||
case edid1_ascii_data:
|
||||
SHOW_INFO( 0, " %s", monitor->data.serial_number );
|
||||
break;
|
||||
case edid1_monitor_ranges: {
|
||||
edid1_monitor_range monitor_range = monitor->data.monitor_range;
|
||||
|
||||
SHOW_INFO( 0, "Horizontal frequency range = %d..%d kHz",
|
||||
monitor_range.min_h, monitor_range.max_h );
|
||||
SHOW_INFO( 0, "Vertical frequency range = %d..%d Hz",
|
||||
monitor_range.min_v, monitor_range.max_v );
|
||||
SHOW_INFO( 0, "Maximum pixel clock = %d MHz", (uint16)monitor_range.max_clock * 10 );
|
||||
break; }
|
||||
case edid1_monitor_name:
|
||||
SHOW_INFO( 0, "Monitor Name: %s", monitor->data.serial_number );
|
||||
break;
|
||||
case edid1_add_colour_pointer: {
|
||||
for( j = 0; j < EDID1_NUM_EXTRA_WHITEPOINTS; ++j ) {
|
||||
edid1_whitepoint *whitepoint = &monitor->data.whitepoint[j];
|
||||
|
||||
if( whitepoint->index == 0 )
|
||||
continue;
|
||||
|
||||
sprintf( buffer, "Additional whitepoint: (X,Y)=(%f,%f) gamma=%f index=%i",
|
||||
whitepoint->white_x / 1024.0,
|
||||
whitepoint->white_y / 1024.0,
|
||||
(whitepoint->gamma + 100) / 100.0,
|
||||
whitepoint->index );
|
||||
SHOW_INFO( 0, "%s", buffer );
|
||||
}
|
||||
break; }
|
||||
case edid1_add_std_timing: {
|
||||
for( j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j ) {
|
||||
edid1_std_timing *timing = &monitor->data.std_timing[j];
|
||||
|
||||
if( timing->h_size <= 256 )
|
||||
continue;
|
||||
|
||||
SHOW_INFO( 0, "%dx%d@%dHz (id=%d)",
|
||||
timing->h_size, timing->v_size,
|
||||
timing->refresh, timing->id );
|
||||
}
|
||||
break; }
|
||||
case edid1_is_detailed_timing: {
|
||||
edid1_detailed_timing *timing = &monitor->data.detailed_timing;
|
||||
|
||||
SHOW_INFO0( 0, "Additional Video Mode:" );
|
||||
sprintf( buffer, "clock=%f MHz", timing->pixel_clock / 100.0 );
|
||||
SHOW_INFO( 0, "%s", buffer );
|
||||
SHOW_INFO( 0, "h: (%d, %d, %d, %d)",
|
||||
timing->h_active, timing->h_active + timing->h_sync_off,
|
||||
timing->h_active + timing->h_sync_off + timing->h_sync_width,
|
||||
timing->h_active + timing->h_blank );
|
||||
SHOW_INFO( 0, "v: (%d, %d, %d, %d)",
|
||||
timing->v_active, timing->v_active + timing->v_sync_off,
|
||||
timing->v_active + timing->v_sync_off + timing->v_sync_width,
|
||||
timing->v_active + timing->v_blank );
|
||||
sprintf( buffer, "size: %.1f cm x %.1f cm",
|
||||
timing->h_size / 10.0, timing->v_size / 10.0 );
|
||||
SHOW_INFO( 0, "%s", buffer );
|
||||
sprintf( buffer, "border: %.1f cm x %.1f cm",
|
||||
timing->h_border / 10.0, timing->v_border / 10.0 );
|
||||
SHOW_INFO( 0, "%s", buffer );
|
||||
break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
EDID handling.
|
||||
*/
|
||||
|
||||
#include "edid.h"
|
||||
#include <KernelExport.h>
|
||||
#include "ddc_int.h"
|
||||
|
||||
//
|
||||
// from hereon a bunch of decoders follow for each EDID section
|
||||
//
|
||||
|
||||
static void decode_vendor( edid1_vendor *vendor, const edid1_vendor_raw *raw )
|
||||
{
|
||||
vendor->manufacturer[0] = raw->c1 + '@';
|
||||
vendor->manufacturer[1] =
|
||||
((raw->c2_high << 3) | raw->c2_low) + '@';
|
||||
vendor->manufacturer[2] = raw->c3 + '@';
|
||||
vendor->manufacturer[3] = 0;
|
||||
vendor->prod_id = B_LENDIAN_TO_HOST_INT16( raw->prod_id );
|
||||
vendor->serial = B_LENDIAN_TO_HOST_INT32( raw->serial );
|
||||
vendor->week = raw->week;
|
||||
vendor->year = raw->year + 1990;
|
||||
}
|
||||
|
||||
static void decode_version( edid1_version *version, const edid1_version_raw *raw )
|
||||
{
|
||||
version->version = raw->version;
|
||||
version->revision = raw->revision;
|
||||
}
|
||||
|
||||
static void decode_display( edid1_display *display, const edid1_display_raw *raw )
|
||||
{
|
||||
display->input_type = raw->input_type;
|
||||
display->input_voltage = raw->input_voltage;
|
||||
display->setup = raw->setup;
|
||||
display->sep_sync = raw->sep_sync;
|
||||
display->comp_sync = raw->comp_sync;
|
||||
display->sync_on_green = raw->sync_on_green;
|
||||
display->sync_serr = raw->sync_serr;
|
||||
|
||||
display->h_size = raw->h_size;
|
||||
display->v_size = raw->v_size;
|
||||
display->gamma = raw->gamma;
|
||||
|
||||
display->dpms_standby = raw->dpms_standby;
|
||||
display->dpms_suspend = raw->dpms_suspend;
|
||||
display->dpms_off = raw->dpms_off;
|
||||
display->display_type = raw->display_type;
|
||||
display->std_colour_space = raw->std_colour_space;
|
||||
display->preferred_timing_mode = raw->preferred_timing_mode;
|
||||
display->gtf_supported = raw->gtf_supported;
|
||||
|
||||
display->red_x = ((uint16)raw->red_x << 2) | raw->red_x_low;
|
||||
display->red_y = ((uint16)raw->red_y << 2) | raw->red_y_low;
|
||||
display->green_x = ((uint16)raw->green_x << 2) | raw->green_x_low;
|
||||
display->green_y = ((uint16)raw->green_y << 2) | raw->green_y_low;
|
||||
display->blue_x = ((uint16)raw->blue_x << 2) | raw->blue_x_low;
|
||||
display->blue_y = ((uint16)raw->blue_y << 2) | raw->blue_y_low;
|
||||
display->white_x = ((uint16)raw->white_x << 2) | raw->white_x_low;
|
||||
display->white_y = ((uint16)raw->white_y << 2) | raw->white_y_low;
|
||||
}
|
||||
|
||||
static void decode_std_timing( edid1_std_timing *timing,
|
||||
const edid1_std_timing_raw *raw )
|
||||
{
|
||||
timing->h_size = (raw->timing.h_size + 31) * 8;
|
||||
timing->ratio = raw->timing.ratio;
|
||||
switch( raw->timing.ratio ) {
|
||||
case 0:
|
||||
timing->v_size = timing->h_size;
|
||||
break;
|
||||
case 1:
|
||||
timing->v_size = timing->h_size * 3 / 4;
|
||||
break;
|
||||
case 2:
|
||||
timing->v_size = timing->h_size * 4 / 5;
|
||||
break;
|
||||
case 3:
|
||||
timing->v_size = timing->h_size * 9 / 16;
|
||||
break;
|
||||
}
|
||||
timing->refresh = raw->timing.refresh + 60;
|
||||
timing->id = raw->id;
|
||||
}
|
||||
|
||||
static void decode_whitepoint( edid1_whitepoint *whitepoint,
|
||||
const edid1_whitepoint_raw *raw )
|
||||
{
|
||||
whitepoint[0].index = raw->index1;
|
||||
whitepoint[0].white_x = ((uint16)raw->white_x1 << 2) | raw->white_x1_low;
|
||||
whitepoint[0].white_y = ((uint16)raw->white_y1 << 2) | raw->white_y1_low;
|
||||
whitepoint[0].gamma = raw->gamma1;
|
||||
|
||||
whitepoint[1].index = raw->index2;
|
||||
whitepoint[1].white_x = ((uint16)raw->white_x2 << 2) | raw->white_x2_low;
|
||||
whitepoint[1].white_y = ((uint16)raw->white_y2 << 2) | raw->white_y2_low;
|
||||
whitepoint[1].gamma = raw->gamma2;
|
||||
}
|
||||
|
||||
static void decode_detailed_timing( edid1_detailed_timing *timing,
|
||||
const edid1_detailed_timing_raw *raw )
|
||||
{
|
||||
timing->pixel_clock = raw->pixel_clock;
|
||||
timing->h_active = ((uint16)raw->h_active_high << 8) | raw->h_active;
|
||||
timing->h_blank = ((uint16)raw->h_blank_high << 8) | raw->h_blank;
|
||||
timing->v_active = ((uint16)raw->v_active_high << 8) | raw->v_active;
|
||||
timing->v_blank = ((uint16)raw->v_blank_high << 8) | raw->v_blank;
|
||||
timing->h_sync_off = ((uint16)raw->h_sync_off_high << 8) | raw->h_sync_off;
|
||||
timing->h_sync_width = ((uint16)raw->h_sync_width_high << 8) | raw->h_sync_width;
|
||||
timing->v_sync_off = ((uint16)raw->v_sync_off_high << 4) | raw->v_sync_off;
|
||||
timing->v_sync_width = ((uint16)raw->v_sync_width_high << 4) | raw->v_sync_width;
|
||||
timing->h_size = ((uint16)raw->h_size_high << 8) | raw->h_size;
|
||||
timing->v_size = ((uint16)raw->v_size_high << 8) | raw->v_size;
|
||||
timing->h_border = raw->h_border;
|
||||
timing->v_border = raw->v_border;
|
||||
timing->interlaced = raw->interlaced;
|
||||
timing->stereo = raw->stereo;
|
||||
timing->sync = raw->sync;
|
||||
timing->misc = raw->misc;
|
||||
}
|
||||
|
||||
// copy string until 0xa, removing trailing spaces
|
||||
static void copy_str( char *dest, const uint8 *src, size_t len )
|
||||
{
|
||||
int i;
|
||||
|
||||
// copy until 0xa
|
||||
for( i = 0; i < (int)len; ++i ) {
|
||||
if( src[i] == 0xa )
|
||||
break;
|
||||
|
||||
*dest++ = *src++;
|
||||
}
|
||||
|
||||
// remove trailing spaces
|
||||
for( i = i - 1; i >= 0; --i ) {
|
||||
if( *dest-- != ' ' )
|
||||
break;
|
||||
}
|
||||
|
||||
*++dest = 0;
|
||||
}
|
||||
|
||||
static void decode_detailed_monitor( edid1_detailed_monitor *monitor,
|
||||
const edid1_detailed_monitor_raw *raw, bool enable_extra )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for( i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i, ++monitor, ++raw ) {
|
||||
monitor->monitor_desc_type = edid1_is_detailed_timing;
|
||||
|
||||
// workaround: normally, all four bytes must be zero for detailed
|
||||
// description, but at least some Formac monitors violate that:
|
||||
// they have some additional info that start at zero_4(!),
|
||||
// so even if only the first two _or_ the other two bytes are
|
||||
// zero, we accept it as a monitor description block
|
||||
if( enable_extra &&
|
||||
((raw->extra.zero_0[0] == 0 && raw->extra.zero_0[1] == 0) ||
|
||||
(raw->extra.zero_0[2] == 0 && raw->extra.zero_4 == 0)) )
|
||||
{
|
||||
monitor->monitor_desc_type = raw->extra.monitor_desc_type;
|
||||
|
||||
switch( raw->extra.monitor_desc_type ) {
|
||||
case edid1_serial_number:
|
||||
copy_str( monitor->data.serial_number,
|
||||
raw->extra.data.serial_number, EDID1_EXTRA_STRING_LEN );
|
||||
break;
|
||||
case edid1_ascii_data:
|
||||
copy_str( monitor->data.ascii_data,
|
||||
raw->extra.data.ascii_data, EDID1_EXTRA_STRING_LEN );
|
||||
break;
|
||||
case edid1_monitor_ranges:
|
||||
monitor->data.monitor_range = raw->extra.data.monitor_range;
|
||||
break;
|
||||
case edid1_monitor_name:
|
||||
copy_str( monitor->data.monitor_name,
|
||||
raw->extra.data.monitor_name, EDID1_EXTRA_STRING_LEN );
|
||||
break;
|
||||
case edid1_add_colour_pointer:
|
||||
decode_whitepoint( monitor->data.whitepoint,
|
||||
&raw->extra.data.whitepoint );
|
||||
break;
|
||||
case edid1_add_std_timing:
|
||||
for( j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j )
|
||||
decode_std_timing( &monitor->data.std_timing[j],
|
||||
&raw->extra.data.std_timing[j] );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
decode_detailed_timing( &monitor->data.detailed_timing,
|
||||
&raw->detailed_timing );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// main function to decode edid data
|
||||
void edid_decode( edid1_info *edid, const edid1_raw *raw )
|
||||
{
|
||||
int i;
|
||||
|
||||
memset( edid, 0, sizeof( edid ));
|
||||
|
||||
decode_vendor( &edid->vendor, &raw->vendor );
|
||||
decode_version( &edid->version, &raw->version );
|
||||
decode_display( &edid->display, &raw->display );
|
||||
|
||||
edid->established_timing = raw->established_timing;
|
||||
|
||||
for( i = 0; i < EDID1_NUM_STD_TIMING; ++i )
|
||||
decode_std_timing( &edid->std_timing[i], &raw->std_timing[i] );
|
||||
|
||||
decode_detailed_monitor( edid->detailed_monitor, raw->detailed_monitor,
|
||||
edid->version.version == 1 && edid->version.revision >= 1 );
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
EDID handling, including decoded EDID data block definitin.
|
||||
*/
|
||||
|
||||
#ifndef _EDID_H
|
||||
#define _EDID_H
|
||||
|
||||
#include "edid_raw.h"
|
||||
|
||||
// vendor info
|
||||
typedef struct {
|
||||
char manufacturer[4];
|
||||
uint16 prod_id;
|
||||
uint32 serial;
|
||||
uint8 week;
|
||||
uint16 year;
|
||||
} edid1_vendor;
|
||||
|
||||
|
||||
// version info
|
||||
typedef struct {
|
||||
uint8 version;
|
||||
uint8 revision;
|
||||
} edid1_version;
|
||||
|
||||
|
||||
// display info
|
||||
typedef struct {
|
||||
BBITFIELD8_7 (
|
||||
input_type : 1, // 1 : digital
|
||||
input_voltage : 2, // 0=0.7V/0.3V, 1=0.714V/0.286,
|
||||
// 2=1V/0.4V, 3=0.7V/0V
|
||||
setup : 1, // true if voltage configurable
|
||||
sep_sync : 1,
|
||||
comp_sync : 1,
|
||||
sync_on_green : 1,
|
||||
sync_serr : 1
|
||||
);
|
||||
uint8 h_size;
|
||||
uint8 v_size;
|
||||
uint8 gamma; // (x+100)/100
|
||||
BBITFIELD8_7 (
|
||||
dpms_standby : 1,
|
||||
dpms_suspend : 1,
|
||||
dpms_off : 1,
|
||||
display_type : 2, // 0=mono, 1=rgb, 2=multicolour
|
||||
// since EDID version 1.1
|
||||
std_colour_space : 1,
|
||||
preferred_timing_mode : 1,
|
||||
gtf_supported : 1
|
||||
);
|
||||
uint16 red_x; // all colours are 0.10 fixed point
|
||||
uint16 red_y;
|
||||
uint16 green_x;
|
||||
uint16 green_y;
|
||||
uint16 blue_x;
|
||||
uint16 blue_y;
|
||||
uint16 white_x;
|
||||
uint16 white_y;
|
||||
} edid1_display;
|
||||
|
||||
|
||||
// standard timing data
|
||||
typedef struct {
|
||||
uint16 h_size;
|
||||
uint16 v_size;
|
||||
uint16 id;
|
||||
uint8 ratio;
|
||||
uint8 refresh;
|
||||
} edid1_std_timing;
|
||||
|
||||
|
||||
// additional whitepoint
|
||||
typedef struct {
|
||||
uint8 index;
|
||||
uint16 white_x;
|
||||
uint16 white_y;
|
||||
uint8 gamma; // (x+100)/100
|
||||
} edid1_whitepoint;
|
||||
|
||||
|
||||
// detailed timing description
|
||||
typedef struct {
|
||||
uint16 pixel_clock; // in 10 kHz
|
||||
uint16 h_active;
|
||||
uint16 h_blank;
|
||||
uint16 v_active;
|
||||
uint16 v_blank;
|
||||
uint16 h_sync_off;
|
||||
uint16 h_sync_width;
|
||||
uint16 v_sync_off;
|
||||
uint16 v_sync_width;
|
||||
uint16 h_size;
|
||||
uint16 v_size;
|
||||
uint16 h_border;
|
||||
uint16 v_border;
|
||||
BBITFIELD8_4 (
|
||||
interlaced : 1,
|
||||
stereo : 2, // upper bit set - left on sync
|
||||
// lower bit set - right on sync
|
||||
sync : 2,
|
||||
misc : 2
|
||||
);
|
||||
} edid1_detailed_timing;
|
||||
|
||||
|
||||
// detailed monitor description
|
||||
typedef struct {
|
||||
uint8 monitor_desc_type;
|
||||
union {
|
||||
char serial_number[EDID1_EXTRA_STRING_LEN];
|
||||
char ascii_data[EDID1_EXTRA_STRING_LEN];
|
||||
edid1_monitor_range monitor_range;
|
||||
char monitor_name[EDID1_EXTRA_STRING_LEN];
|
||||
edid1_whitepoint whitepoint[EDID1_NUM_EXTRA_WHITEPOINTS];
|
||||
edid1_std_timing std_timing[EDID1_NUM_EXTRA_STD_TIMING];
|
||||
edid1_detailed_timing detailed_timing;
|
||||
} data;
|
||||
} edid1_detailed_monitor;
|
||||
|
||||
|
||||
// EDID data block
|
||||
typedef struct{
|
||||
edid1_vendor vendor;
|
||||
edid1_version version;
|
||||
edid1_display display;
|
||||
edid1_established_timing established_timing;
|
||||
edid1_std_timing std_timing[EDID1_NUM_STD_TIMING];
|
||||
|
||||
// since EDID version 1.2
|
||||
edid1_detailed_monitor detailed_monitor[EDID1_NUM_DETAILED_MONITOR_DESC];
|
||||
|
||||
uint8 num_sections;
|
||||
} edid1_info;
|
||||
|
||||
// decode raw EDID info into usuable EDID info
|
||||
void edid_decode( edid1_info *edid, const edid1_raw *raw );
|
||||
// dump EDID info to syslog
|
||||
void edid_dump( edid1_info *edid );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
Raw EDID data block.
|
||||
|
||||
Raw data are packed in a really weird way. Never even
|
||||
think about using it directly, instead translate it via decode_edidpixel_clock
|
||||
first. I did my best to make the code endian-independant, but
|
||||
I cannot guarantee that I haven't a missed something.
|
||||
*/
|
||||
|
||||
#ifndef _EDID_RAW_H
|
||||
#define _EDID_RAW_H
|
||||
|
||||
#include "bendian_bitfield.h"
|
||||
|
||||
#define EDID1_NUM_DETAILED_MONITOR_DESC 4
|
||||
#define EDID1_NUM_STD_TIMING 8
|
||||
#define EDID1_NUM_EXTRA_STD_TIMING 6
|
||||
#define EDID1_EXTRA_STRING_LEN 13
|
||||
#define EDID1_NUM_EXTRA_WHITEPOINTS 2
|
||||
|
||||
|
||||
// header
|
||||
typedef struct _PACKED {
|
||||
int8 pad[8]; // contains 0, -1, -1, -1, -1, -1, -1, 0
|
||||
} edid1_header_raw;
|
||||
|
||||
|
||||
// vendor info
|
||||
typedef struct _PACKED {
|
||||
BBITFIELD8_3 ( // manufacturer
|
||||
pad : 1,
|
||||
c1 : 5, // add '@' to get ascii
|
||||
c2_high : 2
|
||||
);
|
||||
BBITFIELD8_2 (
|
||||
c2_low : 3,
|
||||
c3 : 5
|
||||
);
|
||||
uint16 prod_id;
|
||||
uint32 serial;
|
||||
uint8 week;
|
||||
uint8 year; // x+1990
|
||||
} edid1_vendor_raw;
|
||||
|
||||
|
||||
// version info
|
||||
typedef struct _PACKED {
|
||||
uint8 version;
|
||||
uint8 revision;
|
||||
} edid1_version_raw;
|
||||
|
||||
|
||||
// display info
|
||||
typedef struct _PACKED {
|
||||
BBITFIELD8_7 (
|
||||
input_type : 1, // 1 : digital
|
||||
input_voltage : 2, // 0=0.7V/0.3V, 1=0.714V/0.286,
|
||||
// 2=1V/0.4V, 3=0.7V/0V
|
||||
setup : 1, // true if voltage configurable
|
||||
sep_sync : 1,
|
||||
comp_sync : 1,
|
||||
sync_on_green : 1,
|
||||
sync_serr : 1
|
||||
);
|
||||
uint8 h_size;
|
||||
uint8 v_size;
|
||||
uint8 gamma; // (x+100)/100
|
||||
BBITFIELD8_7 (
|
||||
dpms_standby : 1,
|
||||
dpms_suspend : 1,
|
||||
dpms_off : 1,
|
||||
display_type : 2, // 0=mono, 1=rgb, 2=multicolour
|
||||
// since EDID version 1.1
|
||||
std_colour_space : 1,
|
||||
preferred_timing_mode : 1,
|
||||
gtf_supported : 1
|
||||
);
|
||||
BBITFIELD8_4 ( // low bits of red_x etc.
|
||||
red_x_low : 2,
|
||||
red_y_low : 2,
|
||||
green_x_low : 2,
|
||||
green_y_low : 2
|
||||
);
|
||||
BBITFIELD8_4 (
|
||||
blue_x_low : 2,
|
||||
blue_y_low : 2,
|
||||
white_x_low : 2,
|
||||
white_y_low : 2
|
||||
);
|
||||
uint8 red_x; // all colours are 0.10 fixed point
|
||||
uint8 red_y;
|
||||
uint8 green_x;
|
||||
uint8 green_y;
|
||||
uint8 blue_x;
|
||||
uint8 blue_y;
|
||||
uint8 white_x;
|
||||
uint8 white_y;
|
||||
} edid1_display_raw;
|
||||
|
||||
|
||||
// raw standard timing data
|
||||
typedef union _PACKED {
|
||||
struct _PACKED {
|
||||
uint8 h_size; // (x+31)*8
|
||||
BBITFIELD8_2 (
|
||||
ratio : 2, // 0=1:1, 1=3/4, 2=4/5, 3=9/16
|
||||
refresh : 6 // (x+60)
|
||||
);
|
||||
} timing;
|
||||
uint16 id;
|
||||
} edid1_std_timing_raw;
|
||||
|
||||
|
||||
// list of supported fixed timings
|
||||
typedef struct _PACKED {
|
||||
BBITFIELD8_8 (
|
||||
res_720x400x70 : 1,
|
||||
res_720x400x88 : 1,
|
||||
res_640x480x60 : 1,
|
||||
res_640x480x67 : 1,
|
||||
res_640x480x72 : 1,
|
||||
res_640x480x75 : 1,
|
||||
res_800x600x56 : 1,
|
||||
res_800x600x60 : 1
|
||||
);
|
||||
BBITFIELD8_8 (
|
||||
res_800x600x72 : 1,
|
||||
res_800x600x75 : 1,
|
||||
res_832x624x75 : 1,
|
||||
res_1024x768x87i : 1,
|
||||
res_1024x768x60 : 1,
|
||||
res_1024x768x70 : 1,
|
||||
res_1024x768x75 : 1,
|
||||
res_1280x1024x75 : 1
|
||||
);
|
||||
BBITFIELD8_2 (
|
||||
res_1152x870x75 : 1,
|
||||
pad : 7
|
||||
);
|
||||
} edid1_established_timing;
|
||||
|
||||
|
||||
// types of detailed monitor description
|
||||
enum {
|
||||
edid1_serial_number = 0xff,
|
||||
edid1_ascii_data = 0xfe,
|
||||
edid1_monitor_ranges = 0xfd,
|
||||
edid1_monitor_name = 0xfc,
|
||||
edid1_add_colour_pointer = 0xfb,
|
||||
edid1_add_std_timing = 0xfa,
|
||||
edid1_is_detailed_timing = 1
|
||||
};
|
||||
|
||||
|
||||
// monitor frequency range
|
||||
typedef struct _PACKED {
|
||||
uint8 min_v;
|
||||
uint8 max_v;
|
||||
uint8 min_h;
|
||||
uint8 max_h;
|
||||
uint8 max_clock; // in 10 MHz (!)
|
||||
} edid1_monitor_range;
|
||||
|
||||
|
||||
// additional whitepoint
|
||||
typedef struct _PACKED {
|
||||
uint8 index1;
|
||||
BBITFIELD8_3 (
|
||||
pad1 : 4,
|
||||
white_x1_low : 2,
|
||||
white_y1_low : 2
|
||||
);
|
||||
uint8 white_x1;
|
||||
uint8 white_y1;
|
||||
uint8 gamma1; // (x+100)/100
|
||||
uint8 index2;
|
||||
BBITFIELD8_3 (
|
||||
pad2 : 4,
|
||||
white_x2_low : 2,
|
||||
white_y2_low : 2
|
||||
);
|
||||
uint8 white_x2;
|
||||
uint8 white_y2;
|
||||
uint8 gamma2; // (x+100)/100
|
||||
} edid1_whitepoint_raw;
|
||||
|
||||
|
||||
// detailed timing description
|
||||
typedef struct _PACKED {
|
||||
uint16 pixel_clock; // in 10 kHz (!)
|
||||
uint8 h_active;
|
||||
uint8 h_blank;
|
||||
BBITFIELD8_2 (
|
||||
h_active_high : 4,
|
||||
h_blank_high : 4
|
||||
);
|
||||
uint8 v_active;
|
||||
uint8 v_blank;
|
||||
BBITFIELD8_2 (
|
||||
v_active_high : 4,
|
||||
v_blank_high : 4
|
||||
);
|
||||
uint8 h_sync_off;
|
||||
uint8 h_sync_width;
|
||||
BBITFIELD8_2 (
|
||||
v_sync_off : 4,
|
||||
v_sync_width : 4
|
||||
);
|
||||
BBITFIELD8_4 (
|
||||
h_sync_off_high : 2,
|
||||
h_sync_width_high : 2,
|
||||
v_sync_off_high : 2,
|
||||
v_sync_width_high : 2
|
||||
);
|
||||
uint8 h_size;
|
||||
uint8 v_size;
|
||||
BBITFIELD8_2 (
|
||||
h_size_high : 4,
|
||||
v_size_high : 4
|
||||
);
|
||||
uint8 h_border;
|
||||
uint8 v_border;
|
||||
BBITFIELD8_4 (
|
||||
interlaced : 1,
|
||||
stereo : 2, // upper bit set - left on sync
|
||||
// lower bit set - right on sync
|
||||
sync : 2,
|
||||
misc : 2
|
||||
);
|
||||
} edid1_detailed_timing_raw;
|
||||
|
||||
|
||||
// detailed monitor description
|
||||
typedef union _PACKED {
|
||||
edid1_detailed_timing_raw detailed_timing;
|
||||
struct _PACKED {
|
||||
uint8 zero_0[3];
|
||||
uint8 monitor_desc_type;
|
||||
uint8 zero_4;
|
||||
union _PACKED {
|
||||
uint8 serial_number[EDID1_EXTRA_STRING_LEN];
|
||||
uint8 ascii_data[EDID1_EXTRA_STRING_LEN];
|
||||
uint8 monitor_name[EDID1_EXTRA_STRING_LEN];
|
||||
edid1_monitor_range monitor_range;
|
||||
edid1_whitepoint_raw whitepoint;
|
||||
edid1_std_timing_raw std_timing[EDID1_NUM_EXTRA_STD_TIMING];
|
||||
|
||||
} data;
|
||||
} extra;
|
||||
} edid1_detailed_monitor_raw;
|
||||
|
||||
|
||||
// raw EDID data
|
||||
// everything is packed data, mixture of little endian and big endian
|
||||
// and a bit brain dead overall - nothing your dad would be proud of
|
||||
typedef struct _PACKED {
|
||||
edid1_header_raw header; // 8 bytes
|
||||
edid1_vendor_raw vendor; // 10 bytes
|
||||
edid1_version_raw version; // 2 bytes
|
||||
edid1_display_raw display; // 15 bytes
|
||||
edid1_established_timing established_timing; // 3 bytes
|
||||
edid1_std_timing_raw std_timing[EDID1_NUM_STD_TIMING];
|
||||
// 8 a 2 bytes -> 16 bytes
|
||||
|
||||
// since EDID version 1.2
|
||||
edid1_detailed_monitor_raw detailed_monitor[EDID1_NUM_DETAILED_MONITOR_DESC];
|
||||
// 4 a 18 bytes -> 72 bytes
|
||||
|
||||
uint8 num_sections; // 1 byte
|
||||
uint8 check_sum; // 1 byte
|
||||
} edid1_raw; // total: 128 bytes
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Syncing to graphics card engine
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
//#include "../include/radeon_regs.h"
|
||||
#include "mmio.h"
|
||||
#include "cp_regs.h"
|
||||
#include "pll_regs.h"
|
||||
#include "rbbm_regs.h"
|
||||
#include "buscntrl_regs.h"
|
||||
|
||||
#include "log_coll.h"
|
||||
#include "log_enum.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void Radeon_FlushPixelCache( accelerator_info *ai );
|
||||
|
||||
// send command to purge cache
|
||||
// (may not work with pre-r200 as affected registers
|
||||
// aren't described there)
|
||||
void Radeon_SendPurgeCache( accelerator_info *ai )
|
||||
{
|
||||
uint32 buffer[2];
|
||||
|
||||
buffer[0] = CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 );
|
||||
buffer[1] = RADEON_RB2D_DC_FLUSH_ALL;
|
||||
|
||||
Radeon_SendCP( ai, buffer, 2 );
|
||||
}
|
||||
|
||||
// send command to wait until everything is idle
|
||||
void Radeon_SendWaitUntilIdle( accelerator_info *ai )
|
||||
{
|
||||
uint32 buffer[2];
|
||||
|
||||
buffer[0] = CP_PACKET0( RADEON_WAIT_UNTIL, 0 );
|
||||
buffer[1] = RADEON_WAIT_2D_IDLECLEAN |
|
||||
RADEON_WAIT_3D_IDLECLEAN |
|
||||
RADEON_WAIT_HOST_IDLECLEAN;
|
||||
|
||||
Radeon_SendCP( ai, buffer, 2 );
|
||||
}
|
||||
|
||||
// make sure all drawing is finished
|
||||
void Radeon_Finish( accelerator_info *ai )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
|
||||
LOG( si->log, _Radeon_Finish );
|
||||
|
||||
OUTREG( ai->regs, RADEON_CP_RB_WPTR, si->ring.tail );
|
||||
Radeon_WaitForIdle( ai );
|
||||
Radeon_FlushPixelCache( ai );
|
||||
}
|
||||
|
||||
// wait until engine is idle
|
||||
int Radeon_WaitForIdle( accelerator_info *ai )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
Radeon_WaitForFifo( ai, 64 );
|
||||
|
||||
while( 1 ) {
|
||||
bigtime_t start_time = system_time();
|
||||
|
||||
do {
|
||||
if( (INREG( ai->regs, RADEON_RBBM_STATUS ) & RADEON_RBBM_ACTIVE) == 0 ) {
|
||||
Radeon_FlushPixelCache( ai );
|
||||
return 0;
|
||||
}
|
||||
|
||||
snooze( 1 );
|
||||
} while( system_time() - start_time < 1000000 );
|
||||
|
||||
SHOW_ERROR0( 3, "Engine didn't become idle" );
|
||||
|
||||
LOG( ai->si->log, _Radeon_WaitForIdle );
|
||||
|
||||
Radeon_ResetEngine( ai );
|
||||
}
|
||||
}
|
||||
|
||||
// wait until "entries" FIFO entries are empty
|
||||
void Radeon_WaitForFifo( accelerator_info *ai, int entries )
|
||||
{
|
||||
SHOW_FLOW( 4, "entries=%ld", entries );
|
||||
|
||||
while( 1 ) {
|
||||
bigtime_t start_time = system_time();
|
||||
|
||||
do {
|
||||
int slots = INREG( ai->regs, RADEON_RBBM_STATUS ) & RADEON_RBBM_FIFOCNT_MASK;
|
||||
|
||||
SHOW_FLOW( 4, "empty slots: %ld", slots );
|
||||
|
||||
if ( slots >= entries )
|
||||
return;
|
||||
|
||||
snooze( 1 );
|
||||
} while( system_time() - start_time < 1000000 );
|
||||
|
||||
LOG( ai->si->log, _Radeon_WaitForFifo );
|
||||
|
||||
Radeon_ResetEngine( ai );
|
||||
}
|
||||
}
|
||||
|
||||
// flush pixel cache of graphics card
|
||||
void Radeon_FlushPixelCache( accelerator_info *ai )
|
||||
{
|
||||
bigtime_t start_time;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
OUTREGP( ai->regs, RADEON_RB2D_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL,
|
||||
~RADEON_RB2D_DC_FLUSH_ALL );
|
||||
|
||||
start_time = system_time();
|
||||
|
||||
do {
|
||||
if( (INREG( ai->regs, RADEON_RB2D_DSTCACHE_CTLSTAT )
|
||||
& RADEON_RB2D_DC_BUSY) == 0 )
|
||||
return;
|
||||
|
||||
snooze( 1 );
|
||||
} while( system_time() - start_time < 1000000 );
|
||||
|
||||
LOG( ai->si->log, _Radeon_FlushPixelCache );
|
||||
|
||||
SHOW_ERROR0( 0, "pixel cache didn't become empty" );
|
||||
}
|
||||
|
||||
// reset graphics card's engine
|
||||
void Radeon_ResetEngine( accelerator_info *ai )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
shared_info *si = ai->si;
|
||||
uint32 clock_cntl_index, mclk_cntl, rbbm_soft_reset, host_path_cntl;
|
||||
uint32 cur_read_ptr;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
Radeon_FlushPixelCache( ai );
|
||||
|
||||
clock_cntl_index = INREG( regs, RADEON_CLOCK_CNTL_INDEX );
|
||||
R300_PLLFix( ai );
|
||||
|
||||
// OUCH!
|
||||
// XFree disables any kind of automatic power power management
|
||||
// because of bugs of some ASIC revision (seems like the revisions
|
||||
// cannot be read out)
|
||||
// -> this is a very bad idea, especially when it comes to laptops
|
||||
// I comment it out for now, let's hope noone takes notice
|
||||
if( ai->si->has_crtc2 ) {
|
||||
Radeon_OUTPLLP( ai, RADEON_SCLK_CNTL,
|
||||
RADEON_CP_MAX_DYN_STOP_LAT |
|
||||
RADEON_SCLK_FORCEON_MASK,
|
||||
~RADEON_DYN_STOP_LAT_MASK );
|
||||
|
||||
/* if( ai->si->asic == rt_rv200 ) {
|
||||
Radeon_OUTPLLP( ai, RADEON_SCLK_MORE_CNTL,
|
||||
RADEON_SCLK_MORE_FORCEON, ~0 );
|
||||
}*/
|
||||
}
|
||||
|
||||
mclk_cntl = Radeon_INPLL( ai, RADEON_MCLK_CNTL );
|
||||
|
||||
// enable clock of units to be reset
|
||||
Radeon_OUTPLL( ai, RADEON_MCLK_CNTL, mclk_cntl |
|
||||
RADEON_FORCEON_MCLKA |
|
||||
RADEON_FORCEON_MCLKB |
|
||||
RADEON_FORCEON_YCLKA |
|
||||
RADEON_FORCEON_YCLKB |
|
||||
RADEON_FORCEON_MC |
|
||||
RADEON_FORCEON_AIC );
|
||||
|
||||
// do the reset
|
||||
host_path_cntl = INREG( regs, RADEON_HOST_PATH_CNTL );
|
||||
rbbm_soft_reset = INREG( regs, RADEON_RBBM_SOFT_RESET );
|
||||
|
||||
switch( ai->si->asic ) {
|
||||
case rt_r300:
|
||||
OUTREG( regs, RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
|
||||
RADEON_SOFT_RESET_CP |
|
||||
RADEON_SOFT_RESET_HI |
|
||||
RADEON_SOFT_RESET_E2 |
|
||||
RADEON_SOFT_RESET_AIC ));
|
||||
INREG( regs, RADEON_RBBM_SOFT_RESET);
|
||||
OUTREG( regs, RADEON_RBBM_SOFT_RESET, 0);
|
||||
// this bit has no description
|
||||
OUTREGP( regs, RADEON_RB2D_DSTCACHE_MODE, (1 << 17), ~0 );
|
||||
|
||||
break;
|
||||
default:
|
||||
OUTREG( regs, RADEON_RBBM_SOFT_RESET, rbbm_soft_reset |
|
||||
RADEON_SOFT_RESET_CP |
|
||||
RADEON_SOFT_RESET_HI |
|
||||
RADEON_SOFT_RESET_SE |
|
||||
RADEON_SOFT_RESET_RE |
|
||||
RADEON_SOFT_RESET_PP |
|
||||
RADEON_SOFT_RESET_E2 |
|
||||
RADEON_SOFT_RESET_RB |
|
||||
RADEON_SOFT_RESET_AIC );
|
||||
INREG( regs, RADEON_RBBM_SOFT_RESET );
|
||||
OUTREG( regs, RADEON_RBBM_SOFT_RESET, rbbm_soft_reset &
|
||||
~( RADEON_SOFT_RESET_CP |
|
||||
RADEON_SOFT_RESET_HI |
|
||||
RADEON_SOFT_RESET_SE |
|
||||
RADEON_SOFT_RESET_RE |
|
||||
RADEON_SOFT_RESET_PP |
|
||||
RADEON_SOFT_RESET_E2 |
|
||||
RADEON_SOFT_RESET_RB |
|
||||
RADEON_SOFT_RESET_AIC ) );
|
||||
INREG( regs, RADEON_RBBM_SOFT_RESET );
|
||||
}
|
||||
|
||||
OUTREG( regs, RADEON_HOST_PATH_CNTL, host_path_cntl | RADEON_HDP_SOFT_RESET );
|
||||
INREG( regs, RADEON_HOST_PATH_CNTL );
|
||||
OUTREG( regs, RADEON_HOST_PATH_CNTL, host_path_cntl );
|
||||
|
||||
// restore regs
|
||||
OUTREG( regs, RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
|
||||
|
||||
OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, clock_cntl_index );
|
||||
R300_PLLFix( ai );
|
||||
Radeon_OUTPLL( ai, RADEON_MCLK_CNTL, mclk_cntl );
|
||||
|
||||
// reset ring buffer
|
||||
cur_read_ptr = INREG( regs, RADEON_CP_RB_RPTR );
|
||||
OUTREG( regs, RADEON_CP_RB_WPTR, cur_read_ptr );
|
||||
|
||||
if( si->ring.head ) {
|
||||
*si->ring.head = cur_read_ptr;
|
||||
si->ring.tail = cur_read_ptr;
|
||||
}
|
||||
|
||||
++si->engine.count;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Flat panel support
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include <malloc.h>
|
||||
#include "mmio.h"
|
||||
#include "fp_regs.h"
|
||||
#include "ddc_regs.h"
|
||||
#include "utils.h"
|
||||
#include "ddc.h"
|
||||
|
||||
// calculcate flat panel crtc registers
|
||||
void Radeon_CalcFPRegisters( accelerator_info *ai, virtual_port *port, fp_info *fp_port, display_mode *mode, port_regs *values )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
uint xres = mode->timing.h_display;
|
||||
uint yres = mode->timing.v_display;
|
||||
uint64 Hratio, Vratio;
|
||||
|
||||
// we read old values first, as we only want to change
|
||||
// some bits of them
|
||||
// (in general, we could setup all of them, but noone
|
||||
// else does it, so we don't mess around with them as well)
|
||||
values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL );
|
||||
values->fp_horz_stretch = INREG( regs, RADEON_FP_HORZ_STRETCH );
|
||||
values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH );
|
||||
values->lvds_gen_cntl = INREG( regs, RADEON_LVDS_GEN_CNTL );
|
||||
|
||||
SHOW_FLOW( 2, "before: fp_gen_cntl=%lx, horz=%lx, vert=%lx, lvds_gen_cntl=%lx",
|
||||
values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch,
|
||||
values->lvds_gen_cntl );
|
||||
|
||||
if( xres > fp_port->panel_xres )
|
||||
xres = fp_port->panel_xres;
|
||||
if( yres > fp_port->panel_yres )
|
||||
yres = fp_port->panel_yres;
|
||||
|
||||
// ouch: we must not use floating point in kernel,
|
||||
// we obey and use fixed point instead
|
||||
Hratio = FIX_SCALE * (uint32)xres / fp_port->panel_xres;
|
||||
Vratio = FIX_SCALE * (uint32)yres / fp_port->panel_yres;
|
||||
|
||||
fp_port->h_ratio = Hratio;
|
||||
fp_port->v_ratio = Vratio;
|
||||
|
||||
if( Hratio == FIX_SCALE ) {
|
||||
values->fp_horz_stretch &=
|
||||
~(RADEON_HORZ_STRETCH_BLEND |
|
||||
RADEON_HORZ_STRETCH_ENABLE);
|
||||
} else {
|
||||
uint32 stretch;
|
||||
|
||||
stretch = (uint32)((Hratio * RADEON_HORZ_STRETCH_RATIO_MAX +
|
||||
FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_HORZ_STRETCH_RATIO_MASK;
|
||||
|
||||
values->fp_horz_stretch = stretch
|
||||
| (values->fp_horz_stretch & (RADEON_HORZ_PANEL_SIZE |
|
||||
RADEON_HORZ_FP_LOOP_STRETCH |
|
||||
RADEON_HORZ_AUTO_RATIO_INC));
|
||||
values->fp_horz_stretch |=
|
||||
RADEON_HORZ_STRETCH_BLEND |
|
||||
RADEON_HORZ_STRETCH_ENABLE;
|
||||
}
|
||||
values->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO;
|
||||
|
||||
if( Vratio == FIX_SCALE ) {
|
||||
values->fp_vert_stretch &=
|
||||
~(RADEON_VERT_STRETCH_ENABLE |
|
||||
RADEON_VERT_STRETCH_BLEND);
|
||||
} else {
|
||||
uint32 stretch;
|
||||
|
||||
stretch = (uint32)((Vratio * RADEON_VERT_STRETCH_RATIO_MAX +
|
||||
FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_VERT_STRETCH_RATIO_MASK;
|
||||
|
||||
values->fp_vert_stretch = stretch
|
||||
| (values->fp_vert_stretch & (RADEON_VERT_PANEL_SIZE |
|
||||
RADEON_VERT_STRETCH_RESERVED));
|
||||
values->fp_vert_stretch |=
|
||||
RADEON_VERT_STRETCH_ENABLE |
|
||||
RADEON_VERT_STRETCH_BLEND;
|
||||
}
|
||||
values->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN;
|
||||
|
||||
values->fp_gen_cntl = values->fp_gen_cntl & (uint32)
|
||||
~(RADEON_FP_SEL_CRTC2 |
|
||||
RADEON_FP_RMX_HVSYNC_CONTROL_EN |
|
||||
RADEON_FP_DFP_SYNC_SEL |
|
||||
RADEON_FP_CRT_SYNC_SEL |
|
||||
RADEON_FP_CRTC_LOCK_8DOT |
|
||||
RADEON_FP_USE_SHADOW_EN |
|
||||
RADEON_FP_CRTC_USE_SHADOW_VEND |
|
||||
RADEON_FP_CRT_SYNC_ALT);
|
||||
values->fp_gen_cntl |=
|
||||
RADEON_FP_CRTC_DONT_SHADOW_VPAR |
|
||||
RADEON_FP_CRTC_DONT_SHADOW_HEND;
|
||||
|
||||
values->fp_gen_cntl |= port->is_crtc2 ? RADEON_FP_SEL_CRTC2 : 0;
|
||||
/* values->fp_gen_cntl |= RADEON_FP_SEL_CRTC2;
|
||||
values->fp_gen_cntl &= ~RADEON_FP_USE_SHADOW_EN;*/
|
||||
|
||||
SHOW_FLOW( 3, "FP2: %d", INREG( ai->regs, RADEON_FP2_GEN_CNTL ));
|
||||
|
||||
if( fp_port->disp_type == dt_lvds ) {
|
||||
values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
|
||||
values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
|
||||
} else if( fp_port->disp_type == dt_dvi_1 ) {
|
||||
values->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN);
|
||||
// enabling 8 bit data may be dangerous; BIOS should have taken care of that
|
||||
values->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT;
|
||||
}
|
||||
|
||||
/*values->fp_gen_cntl = RADEON_FP_SEL_CRTC2
|
||||
| RADEON_FP_CRTC_LOCK_8DOT;*/
|
||||
|
||||
SHOW_FLOW( 2, "after: fp_gen_cntl=%lx, horz=%lx, vert=%lx, lvds_gen_cntl=%lx",
|
||||
values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch,
|
||||
values->lvds_gen_cntl );
|
||||
}
|
||||
|
||||
// write flat panel registers
|
||||
void Radeon_ProgramFPRegisters( accelerator_info *ai, fp_info *fp_port, port_regs *values )
|
||||
{
|
||||
uint32 tmp;
|
||||
vuint8 *regs = ai->regs;
|
||||
|
||||
SHOW_FLOW0( 2, "" );
|
||||
|
||||
OUTREG( regs, RADEON_FP_HORZ_STRETCH, values->fp_horz_stretch );
|
||||
OUTREG( regs, RADEON_FP_VERT_STRETCH, values->fp_vert_stretch );
|
||||
OUTREG( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl );
|
||||
|
||||
if( fp_port->disp_type == dt_lvds ) {
|
||||
tmp = INREG( regs, RADEON_LVDS_GEN_CNTL );
|
||||
|
||||
SHOW_FLOW( 3, "old: %x, new: %x", tmp, values->lvds_gen_cntl );
|
||||
|
||||
if((tmp & (RADEON_LVDS_ON | RADEON_LVDS_BLON)) ==
|
||||
(values->lvds_gen_cntl & (RADEON_LVDS_ON | RADEON_LVDS_BLON)) )
|
||||
{
|
||||
SHOW_FLOW0( 3, "Write through" );
|
||||
OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl );
|
||||
} else {
|
||||
if( values->lvds_gen_cntl & (RADEON_LVDS_ON | RADEON_LVDS_BLON) ) {
|
||||
SHOW_FLOW0( 3, "Switching off" );
|
||||
//snooze( fp_port->panel_pwr_delay * 1000);
|
||||
OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl );
|
||||
} else {
|
||||
SHOW_FLOW0( 3, "Switching on" );
|
||||
OUTREG( regs, RADEON_LVDS_GEN_CNTL,
|
||||
values->lvds_gen_cntl | RADEON_LVDS_BLON );
|
||||
//snooze( fp_port->panel_pwr_delay * 1000 );
|
||||
OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
accelerator_info *ai;
|
||||
uint32 port;
|
||||
} ddc_port_info;
|
||||
|
||||
static status_t get_signals( void *cookie, int *clk, int *data )
|
||||
{
|
||||
ddc_port_info *info = (ddc_port_info *)cookie;
|
||||
vuint8 *regs = info->ai->regs;
|
||||
uint32 value;
|
||||
|
||||
value = INREG( regs, info->port );
|
||||
|
||||
*clk = (value >> RADEON_GPIO_Y_SHIFT_1) & 1;
|
||||
*data = (value >> RADEON_GPIO_Y_SHIFT_0) & 1;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t set_signals( void *cookie, int clk, int data )
|
||||
{
|
||||
ddc_port_info *info = (ddc_port_info *)cookie;
|
||||
vuint8 *regs = info->ai->regs;
|
||||
uint32 value;
|
||||
|
||||
value = INREG( regs, info->port );
|
||||
value &= ~(RADEON_GPIO_A_1 | RADEON_GPIO_A_0);
|
||||
value &= ~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1);
|
||||
value |= ((1-clk) << RADEON_GPIO_EN_SHIFT_1) | ((1-data) << RADEON_GPIO_EN_SHIFT_0);
|
||||
|
||||
OUTREG( regs, info->port, value );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// read edid data of flat panel and setup its timing accordingly
|
||||
status_t Radeon_ReadFPEDID( accelerator_info *ai, shared_info *si )
|
||||
{
|
||||
i2c_bus bus;
|
||||
ddc_port_info info;
|
||||
edid1_info edid;
|
||||
fp_info *fp = &si->fp_port;
|
||||
status_t res;
|
||||
void *vdif;
|
||||
size_t vdif_len;
|
||||
uint32 max_hsize, max_vsize;
|
||||
int i;
|
||||
|
||||
info.ai = ai;
|
||||
info.port = RADEON_GPIO_DVI_DDC;
|
||||
// info.port = RADEON_GPIO_VGA_DDC;
|
||||
|
||||
bus.cookie = &info;
|
||||
bus.set_signals = &set_signals;
|
||||
bus.get_signals = &get_signals;
|
||||
|
||||
// get edid
|
||||
res = ddc2_read_edid1( &bus, &edid, &vdif, &vdif_len );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
if( vdif != NULL )
|
||||
free( vdif );
|
||||
|
||||
SHOW_FLOW0( 2, "EDID data read from DVI port via DDC2:" );
|
||||
edid_dump( &edid );
|
||||
|
||||
// find detailed timing with maximum resolution
|
||||
max_hsize = max_vsize = 0;
|
||||
|
||||
for( i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i ) {
|
||||
if( edid.detailed_monitor[i].monitor_desc_type == edid1_is_detailed_timing ) {
|
||||
edid1_detailed_timing *timing = &edid.detailed_monitor[i].data.detailed_timing;
|
||||
|
||||
if( timing->h_size > max_hsize && timing->v_size > max_vsize ) {
|
||||
SHOW_FLOW( 2, "Found DDC data for mode %dx%d",
|
||||
(int)timing->h_active, (int)timing->v_active );
|
||||
|
||||
max_hsize = timing->h_active;
|
||||
max_vsize = timing->v_active;
|
||||
|
||||
// copy it to timing specification
|
||||
fp->panel_xres = timing->h_active;
|
||||
fp->h_blank = timing->h_blank;
|
||||
fp->h_over_plus = timing->h_sync_off;
|
||||
fp->h_sync_width = timing->h_sync_width;
|
||||
|
||||
fp->panel_yres = timing->v_active;
|
||||
fp->v_blank = timing->v_blank;
|
||||
fp->v_over_plus = timing->v_sync_off;
|
||||
fp->v_sync_width = timing->v_sync_width;
|
||||
|
||||
// BeOS uses kHz, but the timing is in 10 kHz
|
||||
fp->dot_clock = timing->pixel_clock * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( max_hsize == 0 )
|
||||
return B_ERROR;
|
||||
|
||||
SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
|
||||
fp->panel_xres, fp->h_blank, fp->h_over_plus, fp->h_sync_width );
|
||||
SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d",
|
||||
fp->panel_yres, fp->v_blank, fp->v_over_plus, fp->v_sync_width );
|
||||
SHOW_INFO( 2, "pixel_clock=%d kHz", fp->dot_clock );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#if !defined(GENERIC_H)
|
||||
#define GENERIC_H
|
||||
|
||||
#include <Accelerant.h>
|
||||
#include "video_overlay.h"
|
||||
|
||||
status_t INIT_ACCELERANT(int fd);
|
||||
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
|
||||
void GET_ACCELERANT_CLONE_INFO(void *data);
|
||||
status_t CLONE_ACCELERANT(void *data);
|
||||
void UNINIT_ACCELERANT(void);
|
||||
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
|
||||
|
||||
uint32 ACCELERANT_MODE_COUNT(void);
|
||||
status_t GET_MODE_LIST(display_mode *dm);
|
||||
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
|
||||
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
|
||||
status_t GET_DISPLAY_MODE(display_mode *current_mode);
|
||||
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
|
||||
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
|
||||
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
|
||||
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
|
||||
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
|
||||
|
||||
uint32 DPMS_CAPABILITIES(void);
|
||||
uint32 DPMS_MODE(void);
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags);
|
||||
|
||||
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
|
||||
void MOVE_CURSOR(uint16 x, uint16 y);
|
||||
void SHOW_CURSOR(bool is_visible);
|
||||
|
||||
uint32 ACCELERANT_ENGINE_COUNT(void);
|
||||
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
|
||||
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
|
||||
void WAIT_ENGINE_IDLE(void);
|
||||
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
|
||||
status_t SYNC_TO_TOKEN(sync_token *st);
|
||||
|
||||
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
|
||||
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
|
||||
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
|
||||
|
||||
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
|
||||
|
||||
uint32 OVERLAY_COUNT(const display_mode *dm);
|
||||
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm);
|
||||
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space);
|
||||
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height);
|
||||
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob);
|
||||
status_t GET_OVERLAY_CONSTRAINTS(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc);
|
||||
overlay_token ALLOCATE_OVERLAY(void);
|
||||
status_t RELEASE_OVERLAY(overlay_token ot);
|
||||
status_t CONFIGURE_OVERLAY(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
I2C protocoll
|
||||
*/
|
||||
|
||||
#include <OS.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#include "ddc_int.h"
|
||||
|
||||
|
||||
// there's no spin in user space, but we need it to wait a couple
|
||||
// of microseconds only
|
||||
// (in this case, snooze has much too much overhead)
|
||||
void spin( bigtime_t delay )
|
||||
{
|
||||
bigtime_t start_time = system_time();
|
||||
|
||||
while( system_time() - start_time < delay )
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
// wait until slave releases clock signal ("clock stretching")
|
||||
static status_t wait_for_clk( const i2c_bus *bus, const i2c_timing *timing,
|
||||
bigtime_t timeout )
|
||||
{
|
||||
bigtime_t start_time;
|
||||
|
||||
// wait for clock signal to raise
|
||||
spin( timing->r );
|
||||
|
||||
start_time = system_time();
|
||||
|
||||
while( 1 ) {
|
||||
int clk, data;
|
||||
|
||||
bus->get_signals( bus->cookie, &clk, &data );
|
||||
if( clk != 0 )
|
||||
return B_OK;
|
||||
|
||||
if( system_time() - start_time > timeout )
|
||||
return B_TIMEOUT;
|
||||
|
||||
spin( timing->r );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// send start or repeated start condition
|
||||
static status_t send_start_condition( const i2c_bus *bus, const i2c_timing *timing )
|
||||
{
|
||||
status_t res;
|
||||
|
||||
bus->set_signals( bus->cookie, 1, 1 );
|
||||
|
||||
res = wait_for_clk( bus, timing, timing->start_timeout );
|
||||
if( res != B_OK ) {
|
||||
SHOW_FLOW0( 2, "Timeout sending start condition" );
|
||||
return res;
|
||||
}
|
||||
|
||||
spin( timing->su_sta );
|
||||
bus->set_signals( bus->cookie, 1, 0 );
|
||||
spin( timing->hd_sta );
|
||||
bus->set_signals( bus->cookie, 0, 0 );
|
||||
spin( timing->f );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// send stop condition
|
||||
static status_t send_stop_condition( const i2c_bus *bus, const i2c_timing *timing )
|
||||
{
|
||||
status_t res;
|
||||
|
||||
bus->set_signals( bus->cookie, 0, 0 );
|
||||
spin( timing->r );
|
||||
bus->set_signals( bus->cookie, 1, 0 );
|
||||
|
||||
// a slave may wait for us, so let elapse the acknowledge timeout
|
||||
// to make the slave release bus control
|
||||
res = wait_for_clk( bus, timing, timing->ack_timeout );
|
||||
if( res != B_OK ) {
|
||||
SHOW_FLOW0( 2, "Timeout sending stop condition" );
|
||||
return res;
|
||||
}
|
||||
|
||||
spin( timing->su_sto );
|
||||
bus->set_signals( bus->cookie, 1, 1 );
|
||||
spin( timing->buf );
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// send one bit
|
||||
static status_t send_bit( const i2c_bus *bus, const i2c_timing *timing, bool bit, int timeout )
|
||||
{
|
||||
status_t res;
|
||||
|
||||
//SHOW_FLOW( 3, "%d", bit & 1 );
|
||||
|
||||
bus->set_signals( bus->cookie, 0, bit & 1 );
|
||||
spin( timing->su_dat );
|
||||
bus->set_signals( bus->cookie, 1, bit & 1 );
|
||||
|
||||
res = wait_for_clk( bus, timing, timeout );
|
||||
if( res != B_OK ) {
|
||||
SHOW_FLOW0( 2, "Timeout when sending next bit" );
|
||||
return res;
|
||||
}
|
||||
|
||||
spin( timing->high );
|
||||
bus->set_signals( bus->cookie, 0, bit & 1 );
|
||||
spin( timing->f + timing->low );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// send acknowledge and wait for reply
|
||||
static status_t send_acknowledge( const i2c_bus *bus, const i2c_timing *timing )
|
||||
{
|
||||
status_t res;
|
||||
bigtime_t start_time;
|
||||
|
||||
// release data so slave can modify it
|
||||
bus->set_signals( bus->cookie, 0, 1 );
|
||||
spin( timing->su_dat );
|
||||
bus->set_signals( bus->cookie, 1, 1 );
|
||||
|
||||
res = wait_for_clk( bus, timing, timing->ack_start_timeout );
|
||||
if( res != B_OK ) {
|
||||
SHOW_FLOW0( 2, "Timeout when sending acknowledge" );
|
||||
return res;
|
||||
}
|
||||
|
||||
// data and clock is high, now wait for slave to pull data low
|
||||
// (according to spec, this can happen any time once clock is high)
|
||||
start_time = system_time();
|
||||
|
||||
while( 1 ) {
|
||||
int clk, data;
|
||||
|
||||
bus->get_signals( bus->cookie, &clk, &data );
|
||||
|
||||
if( data == 0 )
|
||||
break;
|
||||
|
||||
if( system_time() - start_time > timing->ack_timeout ) {
|
||||
SHOW_FLOW0( 2, "Slave didn't acknowledge byte" );
|
||||
return B_TIMEOUT;
|
||||
}
|
||||
|
||||
spin( timing->r );
|
||||
}
|
||||
|
||||
SHOW_FLOW0( 4, "Success!" );
|
||||
|
||||
// make sure we've waited at least t_high
|
||||
spin( timing->high );
|
||||
|
||||
bus->set_signals( bus->cookie, 0, 1 );
|
||||
spin( timing->f + timing->low );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// send byte and wait for acknowledge if <ackowledge> is true
|
||||
static status_t send_byte( const i2c_bus *bus, const i2c_timing *timing,
|
||||
uint8 byte, bool acknowledge )
|
||||
{
|
||||
int i;
|
||||
|
||||
SHOW_FLOW( 2, "%x ", byte );
|
||||
|
||||
for( i = 7; i >= 0; --i ) {
|
||||
status_t res;
|
||||
|
||||
res = send_bit( bus, timing, byte >> i,
|
||||
i == 7 ? timing->byte_timeout : timing->bit_timeout );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
}
|
||||
|
||||
if( acknowledge )
|
||||
return send_acknowledge( bus, timing );
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// send slave address, obeying 10-bit addresses and general call addresses
|
||||
static status_t send_slave_address( const i2c_bus *bus,
|
||||
const i2c_timing *timing, int slave_address, bool is_write )
|
||||
{
|
||||
status_t res;
|
||||
|
||||
res = send_byte( bus, timing, (slave_address & 0xfe) | !is_write, true );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
// there are the following special cases if the first byte looks like:
|
||||
// - 0000 0000 - general call address (second byte with address follows)
|
||||
// - 0000 0001 - start byte
|
||||
// - 0000 001x - CBus address
|
||||
// - 0000 010x - address reserved for different bus format
|
||||
// - 0000 011x |
|
||||
// - 0000 1xxx |-> reserved
|
||||
// - 1111 1xxx |
|
||||
// - 1111 0xxx - 10 bit address (second byte contains remaining 8 bits)
|
||||
|
||||
// the lsb is 0 for write and 1 for read (except for general call address)
|
||||
if( (slave_address & 0xff) != 0 &&
|
||||
(slave_address & 0xf8) != 0xf0 )
|
||||
return B_OK;
|
||||
|
||||
// send second byte if required
|
||||
return send_byte( bus, timing, slave_address >> 8, true );
|
||||
}
|
||||
|
||||
|
||||
// receive one bit
|
||||
static status_t receive_bit( const i2c_bus *bus, const i2c_timing *timing,
|
||||
bool *bit, int timeout )
|
||||
{
|
||||
status_t res;
|
||||
int clk, data;
|
||||
|
||||
// release clock
|
||||
bus->set_signals( bus->cookie, 1, 1 );
|
||||
|
||||
// wait for slave to raise clock
|
||||
res = wait_for_clk( bus, timing, timeout );
|
||||
if( res != B_OK ) {
|
||||
SHOW_FLOW0( 2, "Timeout waiting for bit sent by slave" );
|
||||
return res;
|
||||
}
|
||||
|
||||
// sample data
|
||||
bus->get_signals( bus->cookie, &clk, &data );
|
||||
// leave clock high for minimal time
|
||||
spin( timing->high );
|
||||
// pull clock low so slave waits for us before next bit
|
||||
bus->set_signals( bus->cookie, 0, 1 );
|
||||
// let it settle and leave it low for minimal time
|
||||
// to make sure slave has finished bit transmission too
|
||||
spin( timing->f + timing->low);
|
||||
|
||||
*bit = data;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// receive byte
|
||||
// send positive acknowledge afterwards if <acknowledge> is true, else send negative one
|
||||
static status_t receive_byte( const i2c_bus *bus, const i2c_timing *timing,
|
||||
uint8 *res_byte, bool acknowledge )
|
||||
{
|
||||
uint8 byte = 0;
|
||||
int i;
|
||||
|
||||
// pull clock low to let slave wait for us
|
||||
bus->set_signals( bus->cookie, 0, 1 );
|
||||
|
||||
for( i = 7; i >= 0; --i ) {
|
||||
status_t res;
|
||||
bool bit;
|
||||
|
||||
res = receive_bit( bus, timing, &bit,
|
||||
i == 7 ? timing->byte_timeout : timing->bit_timeout );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
byte = (byte << 1) | bit;
|
||||
}
|
||||
|
||||
//SHOW_FLOW( 3, "%x ", byte );
|
||||
|
||||
*res_byte = byte;
|
||||
|
||||
return send_bit( bus, timing, acknowledge ? 0 : 1, timing->bit_timeout );
|
||||
}
|
||||
|
||||
// send multiple bytes
|
||||
static status_t send_bytes( const i2c_bus *bus, const i2c_timing *timing,
|
||||
const uint8 *write_buffer, ssize_t write_len )
|
||||
{
|
||||
SHOW_FLOW( 3, "len=%ld", write_len );
|
||||
|
||||
for( ; write_len > 0; --write_len, ++write_buffer ) {
|
||||
status_t res;
|
||||
|
||||
res = send_byte( bus, timing, *write_buffer, true );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// receive multiple bytes
|
||||
static status_t receive_bytes( const i2c_bus *bus, const i2c_timing *timing,
|
||||
uint8 *read_buffer, ssize_t read_len )
|
||||
{
|
||||
SHOW_FLOW( 3, "len=%ld", read_len );
|
||||
|
||||
for( ; read_len > 0; --read_len, ++read_buffer ) {
|
||||
status_t res;
|
||||
|
||||
res = receive_byte( bus, timing, read_buffer, read_len > 1 );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// combined i2c send+receive format
|
||||
status_t i2c_send_receive( const i2c_bus *bus, const i2c_timing *timing,
|
||||
int slave_address,
|
||||
const uint8 *write_buffer, size_t write_len,
|
||||
uint8 *read_buffer, size_t read_len )
|
||||
{
|
||||
status_t res;
|
||||
|
||||
res = send_start_condition( bus, timing );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
res = send_slave_address( bus, timing, slave_address, true );
|
||||
if( res != B_OK )
|
||||
goto err;
|
||||
|
||||
res = send_bytes( bus, timing, write_buffer, write_len );
|
||||
if( res != B_OK )
|
||||
goto err;
|
||||
|
||||
res = send_start_condition( bus, timing );
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
res = send_slave_address( bus, timing, slave_address, false );
|
||||
if( res != B_OK )
|
||||
goto err;
|
||||
|
||||
res = receive_bytes( bus, timing, read_buffer, read_len );
|
||||
if( res != B_OK )
|
||||
goto err;
|
||||
|
||||
res = send_stop_condition( bus, timing );
|
||||
return res;
|
||||
|
||||
err:
|
||||
SHOW_FLOW0( 2, "Cancelling transmission" );
|
||||
send_stop_condition( bus, timing );
|
||||
return res;
|
||||
}
|
||||
|
||||
// timining for 100kHz bus (fractional parts are rounded up)
|
||||
i2c_timing i2c_timing_100k =
|
||||
{
|
||||
buf : 5,
|
||||
hd_sta : 4,
|
||||
low : 5,
|
||||
high : 4,
|
||||
su_sta : 5,
|
||||
hd_dat : 0,
|
||||
su_dat : 1,
|
||||
r : 1,
|
||||
f : 1,
|
||||
su_sto : 4,
|
||||
|
||||
// as these are unspecified, we use half a clock cycle as a safe guess
|
||||
start_timeout : 5,
|
||||
byte_timeout : 5,
|
||||
bit_timeout : 5,
|
||||
ack_start_timeout : 5,
|
||||
ack_timeout : 5
|
||||
};
|
||||
|
||||
// timing for 400 kHz bus
|
||||
// (argh! heavy up-rounding here)
|
||||
i2c_timing i2c_timing_400k =
|
||||
{
|
||||
buf : 2,
|
||||
hd_sta : 1,
|
||||
low : 2,
|
||||
high : 1,
|
||||
su_sta : 1,
|
||||
hd_dat : 0,
|
||||
su_dat : 1,
|
||||
r : 1,
|
||||
f : 1,
|
||||
su_sto : 1,
|
||||
|
||||
// see i2c_timing_100k
|
||||
start_timeout : 2,
|
||||
byte_timeout : 2,
|
||||
bit_timeout : 2,
|
||||
ack_start_timeout : 2,
|
||||
ack_timeout : 2
|
||||
};
|
||||
|
||||
void i2c_get100k_timing( i2c_timing *timing )
|
||||
{
|
||||
*timing = i2c_timing_100k;
|
||||
}
|
||||
|
||||
void i2c_get400k_timing( i2c_timing *timing )
|
||||
{
|
||||
*timing = i2c_timing_400k;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
I2C protocoll
|
||||
*/
|
||||
|
||||
#ifndef _I2C_H
|
||||
#define _I2C_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
// timing for i2c bus
|
||||
typedef struct i2c_timing {
|
||||
// general timing as defined by standard
|
||||
// (in microseconds for 100kHz/400kHz mode)
|
||||
int buf; // bus free between start and stop (4.7/1.3)
|
||||
int hd_sta; // hold time start condition (4.0/0.6)
|
||||
int low; // low period of clock (4.7/1.3)
|
||||
int high; // high period of clock (4.0/0.6)
|
||||
int su_sta; // setup time of repeated start condition (4.7/0.6)
|
||||
int hd_dat; // hold time data (5.0/- for CBUS, 0/0 for I2C)
|
||||
int su_dat; // setup time data (0.250/0.100)
|
||||
int r; // maximum raise time of clock and data signal (1.0/0.3)
|
||||
int f; // maximum fall time of clock and data signal (0.3/0.3)
|
||||
int su_sto; // setup time for stop condition (4.0/0.6)
|
||||
|
||||
// clock stretching limits, not part of i2c standard
|
||||
int start_timeout; // max. delay of start condition
|
||||
int byte_timeout; // max. delay of first bit of byte
|
||||
int bit_timeout; // max. delay of one bit within a byte transmission
|
||||
int ack_start_timeout; // max. delay of acknowledge start
|
||||
|
||||
// other timeouts, not part of i2c standard
|
||||
int ack_timeout; // timeout of waiting for acknowledge
|
||||
} i2c_timing;
|
||||
|
||||
|
||||
// set signals on bus
|
||||
typedef status_t (*i2c_set_signals)( void *cookie, int scl, int sda );
|
||||
// read signals from bus
|
||||
typedef status_t (*i2c_get_signals)( void *cookie, int *scl, int *sda );
|
||||
|
||||
|
||||
// i2c bus definition
|
||||
typedef struct i2c_bus {
|
||||
void *cookie; // user-defined cookie
|
||||
i2c_set_signals set_signals; // callback to set signals
|
||||
i2c_get_signals get_signals; // callback to detect signals
|
||||
} i2c_bus;
|
||||
|
||||
|
||||
// send and receive data via i2c bus
|
||||
status_t i2c_send_receive( const i2c_bus *bus, const i2c_timing *timing,
|
||||
int slave_address,
|
||||
const uint8 *write_buffer, size_t write_len,
|
||||
uint8 *read_buffer, size_t read_len );
|
||||
|
||||
|
||||
// fill <timing> with standard 100kHz bus timing
|
||||
void i2c_get100k_timing( i2c_timing *timing );
|
||||
|
||||
// fill <timing> with standard 400kHz bus timing
|
||||
// (as timing resolution is 1 microsecond, we cannot reach full speed!)
|
||||
void i2c_get400k_timing( i2c_timing *timing );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
Both kernel and user space part.
|
||||
(init and clean-up must be done in
|
||||
kernel space).
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <perfmon_kernel.h>
|
||||
#include "log_coll.h"
|
||||
#include <OS.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct log_info_t {
|
||||
char *log_buffer;
|
||||
uint32 log_buffer_len;
|
||||
uint32 log_buffer_pos;
|
||||
area_id area;
|
||||
} log_info;
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
|
||||
|
||||
// write one log entry
|
||||
void log( log_info *li, uint16 what, const uint8 num_args, ... )
|
||||
{
|
||||
uint32 pos;
|
||||
va_list vl;
|
||||
log_entry *entry;
|
||||
uint32 i;
|
||||
uint32 entry_size;
|
||||
|
||||
entry_size = sizeof( log_entry ) + (num_args - 1) * sizeof( uint32 );
|
||||
pos = atomic_add( &li->log_buffer_pos, entry_size );
|
||||
|
||||
if( li->log_buffer_pos > li->log_buffer_len ) {
|
||||
atomic_add( &li->log_buffer_pos, -entry_size );
|
||||
return;
|
||||
}
|
||||
|
||||
entry = (log_entry *)&li->log_buffer[pos];
|
||||
|
||||
entry->tsc = read_tsc();
|
||||
entry->what = what;
|
||||
entry->num_args = num_args;
|
||||
|
||||
va_start( vl, num_args );
|
||||
for( i = 0; i < num_args; ++i ) {
|
||||
entry->args[i] = va_arg( vl, uint32 );
|
||||
}
|
||||
va_end( vl );
|
||||
}
|
||||
|
||||
#ifdef LOG_INCLUDE_STARTUP
|
||||
|
||||
// create log buffer
|
||||
log_info *log_init( uint32 size )
|
||||
{
|
||||
log_info *li;
|
||||
area_id area;
|
||||
|
||||
// buffer must be accessible from user mem
|
||||
// to allow logging from there as well;
|
||||
// you cannot clone this area as there are
|
||||
// pointers which would break (it wouldn't be
|
||||
// hard to get rid of them, but I don't care
|
||||
// and keep it as simple as possible)
|
||||
area = create_area( "fast_logger",
|
||||
(void **)&li, B_ANY_KERNEL_ADDRESS,
|
||||
(sizeof( log_info ) + size + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1),
|
||||
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA );
|
||||
|
||||
if( area < 0 )
|
||||
panic( "Radeon Fast logger: cannot allocate %ld byte for logging data\n", size );
|
||||
|
||||
li->area = area;
|
||||
li->log_buffer = (char *)li + sizeof( log_info );
|
||||
li->log_buffer_len = size;
|
||||
li->log_buffer_pos = 0;
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
// clean-up logging
|
||||
void log_exit( log_info *li )
|
||||
{
|
||||
li->log_buffer_pos = 0;
|
||||
//free( li->log_buffer );
|
||||
delete_area( li->area );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LOG_INCLUDE_STARTUP
|
||||
|
||||
// get *current* size of logging data
|
||||
uint32 log_getsize( log_info *li )
|
||||
{
|
||||
if( li == NULL )
|
||||
return 0;
|
||||
|
||||
dprintf( "RADEON -- log_getsize: log_pos %ld\n", li->log_buffer_pos );
|
||||
return li->log_buffer_pos;
|
||||
}
|
||||
|
||||
// get up to max_size bytes of logging data
|
||||
void log_getcopy( log_info *li, void *dest, uint32 max_size )
|
||||
{
|
||||
if( li == NULL )
|
||||
return;
|
||||
|
||||
dprintf( "RADEON -- log_getcopy: max_size %ld, log_pos %ld\n",
|
||||
max_size, li->log_buffer_pos );
|
||||
memcpy( dest, li->log_buffer, min( li->log_buffer_pos, max_size ));
|
||||
|
||||
li->log_buffer_pos = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
Fast logger
|
||||
|
||||
As syslog is very slow and tends to loose
|
||||
data if its buffer overflows (which occurs much
|
||||
too often), this module provides a fast (and memory-
|
||||
wasting) logging mechanism. You need a seperate
|
||||
application to retrieve the log.
|
||||
|
||||
Everything is thread-safe.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LOG_COLL_H__
|
||||
#define __LOG_COLL_H__
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// by undefining this flag, all logging functions
|
||||
// are resolved to empty space, so don't add
|
||||
// extra tests in your code
|
||||
#undef ENABLE_LOGGING
|
||||
//#define ENABLE_LOGGING
|
||||
|
||||
|
||||
// add log entry with 0..3 (uint32) data
|
||||
#define LOG( li, what ) log( li, what, 0 )
|
||||
#define LOG1( li, what, arg1 ) log( li, what, 1, arg1 );
|
||||
#define LOG2( li, what, arg1, arg2 ) log( li, what, 2, arg1, arg2 );
|
||||
#define LOG3( li, what, arg1, arg2, arg3 ) log( li, what, 3, arg1, arg2, arg3 );
|
||||
|
||||
|
||||
// one log entry
|
||||
typedef struct log_entry_t {
|
||||
uint64 tsc;
|
||||
uint16 what;
|
||||
uint8 num_args;
|
||||
uint32 args[1];
|
||||
} log_entry;
|
||||
|
||||
struct log_info_t;
|
||||
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
void log( struct log_info_t *li, uint16 what, const uint8 num_args, ... );
|
||||
#else
|
||||
#define log( a, b, c, ... )
|
||||
#endif
|
||||
|
||||
|
||||
// define LOG_INCLUDE_STARTUP in your device driver
|
||||
#ifdef LOG_INCLUDE_STARTUP
|
||||
|
||||
uint32 log_getsize( struct log_info_t *li );
|
||||
void log_getcopy( struct log_info_t *li, void *dest, uint32 max_size );
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
|
||||
struct log_info_t *log_init( uint32 size );
|
||||
void log_exit( struct log_info_t *li );
|
||||
|
||||
#else
|
||||
|
||||
#define log_init( a ) NULL
|
||||
#define log_exit( a )
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
Fast logger - functions to create dump
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "log_coll.h"
|
||||
#include "log_dump.h"
|
||||
#include "log_enum.h"
|
||||
#include "log_names.h"
|
||||
|
||||
void log_printentry( FILE *logfile, log_entry *entry );
|
||||
|
||||
system_info sysinfo;
|
||||
|
||||
// dump one entry
|
||||
void log_printentry( FILE *logfile, log_entry *entry )
|
||||
{
|
||||
uint64 time;
|
||||
uint32 min, sec, mill, mic;
|
||||
|
||||
time = entry->tsc / (sysinfo.cpu_clock_speed / 1000000);
|
||||
mic = time % 1000;
|
||||
time /= 1000;
|
||||
mill = time % 1000;
|
||||
time /= 1000;
|
||||
sec = time % 60;
|
||||
time /= 60;
|
||||
min = time;
|
||||
|
||||
fprintf( logfile, "%03ld:%02ld:%03ld.%03ld ", min, sec, mill, mic );
|
||||
if( entry->what < sizeof( log_names ) / sizeof( log_names[0] ) )
|
||||
fprintf( logfile, log_names[entry->what] );
|
||||
else
|
||||
fprintf( logfile, "unknown %ld", (uint32)entry->what );
|
||||
|
||||
if( entry->num_args > 0 ) {
|
||||
uint32 i;
|
||||
|
||||
fprintf( logfile, " (" );
|
||||
for( i = 0; i < entry->num_args; ++i ) {
|
||||
if( i > 0 )
|
||||
fprintf( logfile, ", " );
|
||||
|
||||
fprintf( logfile, "0x%08lx", entry->args[i] );
|
||||
}
|
||||
fprintf( logfile, ")" );
|
||||
}
|
||||
|
||||
fprintf( logfile, "\n" );
|
||||
}
|
||||
|
||||
|
||||
// dump entire log
|
||||
void log_printall( FILE *logfile, char *buffer, uint32 buffer_len )
|
||||
{
|
||||
uint32 pos;
|
||||
|
||||
get_system_info( &sysinfo );
|
||||
|
||||
for( pos = 0; pos < buffer_len; ) {
|
||||
log_entry *entry;
|
||||
|
||||
entry = (log_entry *)(buffer + pos);
|
||||
log_printentry( logfile, entry/*, &tsc*/ );
|
||||
pos += sizeof( log_entry ) + (entry->num_args - 1) * sizeof( uint32 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Fast logger - functions to create dump
|
||||
*/
|
||||
|
||||
#ifndef __LOG_DUMP_H__
|
||||
#define __LOG_DUMP_H__
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
void log_printall( FILE *logfile, char *buffer, uint32 buffer_len );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
Fast logger - event codes
|
||||
*/
|
||||
|
||||
enum {
|
||||
_Radeon_FlushPixelCache,
|
||||
_Radeon_WaitForFifo,
|
||||
_Radeon_WaitForIdle,
|
||||
_Radeon_WriteRegFifo,
|
||||
_GetAvailRingBufferQueue,
|
||||
_Radeon_Finish,
|
||||
_Radeon_SendCP,
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
Fast logger - event names
|
||||
*/
|
||||
|
||||
char *log_names[] = {
|
||||
"_Radeon_FlushPixelCache",
|
||||
"_Radeon_WaitForFifo",
|
||||
"_Radeon_WaitForIdle",
|
||||
"_Radeon_WriteRegFifo",
|
||||
"_GetAvailRingBufferQueue",
|
||||
"_Radeon_Finish",
|
||||
"_Radeon_SendCP",
|
||||
};
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Multi-monitor management
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "generic.h"
|
||||
#include "GlobalData.h"
|
||||
|
||||
|
||||
// transform official mode to internal, multi-screen mode enhanced mode
|
||||
void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
|
||||
{
|
||||
// uint32 x, y, offset;
|
||||
|
||||
mode->timing.flags &= ~RADEON_MODE_MASK;
|
||||
|
||||
switch( vc->wanted_multi_mode ) {
|
||||
case mm_mirror:
|
||||
mode->timing.flags |= RADEON_MODE_MIRROR;
|
||||
break;
|
||||
case mm_clone:
|
||||
mode->timing.flags |= RADEON_MODE_CLONE;
|
||||
break;
|
||||
case mm_combine:
|
||||
mode->timing.flags |= RADEON_MODE_COMBINE;
|
||||
break;
|
||||
case mm_none:
|
||||
default:
|
||||
}
|
||||
|
||||
// swap displays if asked for
|
||||
if( vc->swapDisplays )
|
||||
mode->timing.flags |= RADEON_MODE_DISPLAYS_SWAPPED;
|
||||
else
|
||||
mode->timing.flags &= ~RADEON_MODE_DISPLAYS_SWAPPED;
|
||||
|
||||
// combine mode is used if virtual area is twice as visible area
|
||||
// and if scrolling is enabled; if combining is impossible, use
|
||||
// cloning instead
|
||||
if( (mode->flags & B_SCROLL) == 0 ) {
|
||||
if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE ) {
|
||||
SHOW_FLOW0( 3, "This isn't a combine mode, falling back to clone" );
|
||||
mode->timing.flags &= ~RADEON_MODE_MASK;
|
||||
mode->timing.flags |= RADEON_MODE_CLONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SHOW_FLOW0( 3, "possibly combine mode" );
|
||||
|
||||
// remove scroll flag - we don't need it anymore
|
||||
mode->flags &= ~B_SCROLL;
|
||||
|
||||
mode->timing.flags &= ~RADEON_MODE_POSITION_MASK;
|
||||
|
||||
if( mode->virtual_width == 2 * mode->timing.h_display ) {
|
||||
SHOW_FLOW0( 3, "horizontal combine mode" );
|
||||
mode->timing.flags |= RADEON_MODE_POSITION_HORIZONTAL;
|
||||
mode->timing.flags &= ~RADEON_MODE_MASK;
|
||||
mode->timing.flags |= RADEON_MODE_COMBINE;
|
||||
} else if( mode->virtual_height == 2 * mode->timing.v_display ) {
|
||||
SHOW_FLOW0( 3, "vertical combine mode" );
|
||||
mode->timing.flags |= RADEON_MODE_POSITION_VERTICAL;
|
||||
mode->timing.flags &= ~RADEON_MODE_MASK;
|
||||
mode->timing.flags |= RADEON_MODE_COMBINE;
|
||||
} else {
|
||||
// ups, this isn't really a combine mode - restore flags
|
||||
SHOW_FLOW0( 3, "wasn't really a combine mode" );
|
||||
mode->timing.flags &= ~RADEON_MODE_MASK;
|
||||
mode->timing.flags |= RADEON_MODE_CLONE;
|
||||
mode->flags |= ~B_SCROLL;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure selected multi-screen mode is valid; adapt it if needed
|
||||
void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode )
|
||||
{
|
||||
// if there is no second port or no second monitor connected,
|
||||
// fall back to standard mode
|
||||
if( vc->num_ports == 1 ||
|
||||
(si->ports[vc->ports[0].physical_port].disp_type == dt_none ||
|
||||
si->ports[vc->ports[1].physical_port].disp_type == dt_none) )
|
||||
{
|
||||
SHOW_FLOW0( 3, "only one monitor - disabling any multi-mon mode" );
|
||||
// restore flags if combine mode is selected
|
||||
if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
|
||||
mode->flags |= B_SCROLL;
|
||||
|
||||
mode->timing.flags &= ~RADEON_MODE_MASK;
|
||||
mode->timing.flags |= RADEON_MODE_STANDARD;
|
||||
}
|
||||
}
|
||||
|
||||
// transform internal, multi-screen enabled display mode
|
||||
// to official mode
|
||||
void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
|
||||
{
|
||||
// restore flags for combine mode
|
||||
if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
|
||||
mode->flags |= B_SCROLL;
|
||||
}
|
||||
|
||||
|
||||
// initialize multi-screen mode dependant variables
|
||||
void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode )
|
||||
{
|
||||
// uint32 offset;
|
||||
uint32 x, y;
|
||||
|
||||
// setup single-screen mode
|
||||
vc->eff_width = mode->timing.h_display;
|
||||
vc->eff_height = mode->timing.v_display;
|
||||
|
||||
vc->ports[0].rel_x = 0;
|
||||
vc->ports[0].rel_y = 0;
|
||||
|
||||
switch( mode->timing.flags & RADEON_MODE_MASK ) {
|
||||
case RADEON_MODE_CLONE:
|
||||
// in clone mode, ports are independant but show the same
|
||||
vc->ports[1].rel_x = 0;
|
||||
vc->ports[1].rel_y = 0;
|
||||
break;
|
||||
|
||||
case RADEON_MODE_COMBINE:
|
||||
// detect where second screen must be located and
|
||||
// adapt total visible area accordingly
|
||||
if( (mode->timing.flags & RADEON_MODE_POSITION_MASK) == RADEON_MODE_POSITION_HORIZONTAL ) {
|
||||
vc->eff_width = 2 * mode->timing.h_display;
|
||||
x = mode->timing.h_display;
|
||||
y = 0;
|
||||
} else {
|
||||
vc->eff_height = 2 * mode->timing.v_display;
|
||||
x = 0;
|
||||
y = mode->timing.v_display;
|
||||
}
|
||||
|
||||
SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
|
||||
|
||||
vc->ports[1].rel_x = 0;
|
||||
vc->ports[1].rel_y = 0;
|
||||
|
||||
// set relative offset
|
||||
if( (mode->timing.flags & RADEON_MODE_DISPLAYS_SWAPPED) == 0 ) {
|
||||
vc->ports[1].rel_x = x;
|
||||
vc->ports[1].rel_y = y;
|
||||
} else {
|
||||
vc->ports[0].rel_x = x;
|
||||
vc->ports[0].rel_y = y;
|
||||
}
|
||||
break;
|
||||
|
||||
case RADEON_MODE_STANDARD:
|
||||
case RADEON_MODE_MIRROR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check and execute tunnel settings command
|
||||
status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
|
||||
const display_mode *low, const display_mode *high, bool *isTunneled )
|
||||
{
|
||||
if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 &&
|
||||
(mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 )
|
||||
{
|
||||
mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST;
|
||||
mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY;
|
||||
|
||||
// still process request, just in case someone set this flag
|
||||
// combination by mistake
|
||||
|
||||
// TBD: disabled to shorten syslog
|
||||
*isTunneled = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// check magic params
|
||||
if( mode->space != 0 || low->space != 0 || high->space != 0
|
||||
|| low->virtual_width != 0xffff || low->virtual_height != 0xffff
|
||||
|| high->virtual_width != 0 || high->virtual_height != 0
|
||||
|| mode->timing.pixel_clock != 0
|
||||
|| low->timing.pixel_clock != 'TKTK' || high->timing.pixel_clock != 'KTKT' )
|
||||
{
|
||||
*isTunneled = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
*isTunneled = true;
|
||||
|
||||
switch( mode->h_display_start ) {
|
||||
case ms_swap:
|
||||
if( mode->v_display_start != 0 )
|
||||
vc->swapDisplays = mode->timing.flags != 0;
|
||||
else
|
||||
mode->timing.flags = vc->swapDisplays;
|
||||
|
||||
// write settings instantly
|
||||
Radeon_WriteSettings( vc );
|
||||
return B_OK;
|
||||
|
||||
/* case ms_overlay_port:
|
||||
if( mode->v_display_start != 0 )
|
||||
vc->whished_overlay_port = mode->timing.flags;
|
||||
else
|
||||
mode->timing.flags = vc->whished_overlay_port;
|
||||
|
||||
Radeon_WriteSettings( vc );
|
||||
return B_OK;*/
|
||||
|
||||
default:
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return true if both ports must be programmed
|
||||
bool Radeon_NeedsSecondPort( display_mode *mode )
|
||||
{
|
||||
switch( mode->timing.flags & RADEON_MODE_MASK ) {
|
||||
case RADEON_MODE_COMBINE:
|
||||
case RADEON_MODE_CLONE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// return number of ports showing differents parts of frame buffer
|
||||
bool Radeon_DifferentPorts( display_mode *mode )
|
||||
{
|
||||
switch( mode->timing.flags & RADEON_MODE_MASK ) {
|
||||
case RADEON_MODE_COMBINE:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Overlay interface
|
||||
*/
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "radeon_interface.h"
|
||||
#include "video_overlay.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include "overlay_regs.h"
|
||||
|
||||
uint32 OVERLAY_COUNT( const display_mode *dm );
|
||||
const uint32 *OVERLAY_SUPPORTED_SPACES( const display_mode *dm );
|
||||
uint32 OVERLAY_SUPPORTED_FEATURES( uint32 color_space );
|
||||
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uint16 height );
|
||||
status_t RELEASE_OVERLAY_BUFFER( const overlay_buffer *ob );
|
||||
status_t GET_OVERLAY_CONSTRAINTS( const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc );
|
||||
overlay_token ALLOCATE_OVERLAY( void );
|
||||
status_t RELEASE_OVERLAY(overlay_token ot);
|
||||
status_t CONFIGURE_OVERLAY( overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov );
|
||||
|
||||
// we could add support of planar modes and YUV modes
|
||||
// but I neither know how planar modes are defined nor
|
||||
// whether there is any program that makes use of them
|
||||
static uint32 overlay_colorspaces [] =
|
||||
{
|
||||
B_RGB15, B_RGB16, B_RGB32, B_YCbCr422, 0
|
||||
};
|
||||
|
||||
|
||||
// public function: number of overlay units
|
||||
uint32 OVERLAY_COUNT( const display_mode *dm )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// public function: return list of supported overlay colour spaces
|
||||
// dm - display mode where overlay is to be used
|
||||
const uint32 *OVERLAY_SUPPORTED_SPACES( const display_mode *dm )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
return overlay_colorspaces;
|
||||
}
|
||||
|
||||
|
||||
// public function: returns supported features
|
||||
// color_space - overlay's colour space
|
||||
uint32 OVERLAY_SUPPORTED_FEATURES( uint32 color_space )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
return
|
||||
B_OVERLAY_COLOR_KEY |
|
||||
B_OVERLAY_HORIZONTAL_FILTERING |
|
||||
B_OVERLAY_VERTICAL_FILTERING;
|
||||
}
|
||||
|
||||
|
||||
// public function: allocates overlay buffer
|
||||
// cs - overlay's colour space
|
||||
// width, height - width and height of overlay buffer
|
||||
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uint16 height )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
radeon_alloc_local_mem am;
|
||||
overlay_buffer_node *node;
|
||||
overlay_buffer *buffer;
|
||||
status_t result;
|
||||
uint ati_space, test_reg, bpp;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
switch( cs ) {
|
||||
case B_RGB15:
|
||||
SHOW_FLOW0( 3, "RGB15" );
|
||||
bpp = 2;
|
||||
ati_space = RADEON_SCALER_SOURCE_15BPP >> 8;
|
||||
test_reg = 0;
|
||||
break;
|
||||
case B_RGB16:
|
||||
SHOW_FLOW0( 3, "RGB16" );
|
||||
bpp = 2;
|
||||
ati_space = RADEON_SCALER_SOURCE_16BPP >> 8;
|
||||
test_reg = 0;
|
||||
break;
|
||||
case B_RGB32:
|
||||
SHOW_FLOW0( 3, "RGB32" );
|
||||
bpp = 4;
|
||||
ati_space = RADEON_SCALER_SOURCE_32BPP >> 8;
|
||||
test_reg = 0;
|
||||
break;
|
||||
case B_YCbCr422:
|
||||
SHOW_FLOW0( 3, "YCbCr422" );
|
||||
bpp = 2;
|
||||
// strange naming convention: VYUY has to be read backward,
|
||||
// i.e. you get (low to high address) YUYV, which is what we want!
|
||||
ati_space = RADEON_SCALER_SOURCE_VYUY422 >> 8;
|
||||
test_reg = 0;
|
||||
break;
|
||||
// YUV12 is planar pixel format consisting of two or three planes
|
||||
// I have no clue whether and how this format is used in BeOS
|
||||
// (don't even know how it is defined officially)
|
||||
/* case B_YUV12:
|
||||
SHOW_FLOW0( 3, "YUV12" );
|
||||
bpp = 2;
|
||||
uvpp = 1;
|
||||
ati_space = RADEON_SCALER_SOURCE_YUV12 >> 8;
|
||||
testreg = 0;
|
||||
break;*/
|
||||
default:
|
||||
SHOW_FLOW( 3, "Unsupported format (%x)", (int)cs );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = malloc( sizeof( overlay_buffer_node ));
|
||||
if( node == NULL )
|
||||
return NULL;
|
||||
|
||||
node->ati_space = ati_space;
|
||||
node->test_reg = test_reg;
|
||||
|
||||
ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
// alloc graphics mem
|
||||
buffer = &node->buffer;
|
||||
|
||||
buffer->space = cs;
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->bytes_per_row = (width * bpp + 0xf) & ~0xf;
|
||||
|
||||
am.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
am.size = buffer->bytes_per_row * height;
|
||||
|
||||
result = ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am );
|
||||
if( result != B_OK )
|
||||
goto err;
|
||||
|
||||
node->mem_handle = am.handle;
|
||||
node->mem_offset = am.fb_offset;
|
||||
buffer->buffer = (int8*)si->framebuffer + am.fb_offset;
|
||||
buffer->buffer_dma = (int8*)si->framebuffer_pci + am.fb_offset;
|
||||
|
||||
// add to list of overlays
|
||||
node->next = vc->overlay_buffers;
|
||||
node->prev = NULL;
|
||||
if( node->next )
|
||||
node->next->prev = node;
|
||||
|
||||
vc->overlay_buffers = node;
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
|
||||
SHOW_FLOW( 3, "success: mem_handle=%x, offset=%x", node->mem_handle, node->mem_offset );
|
||||
|
||||
return buffer;
|
||||
|
||||
err:
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// public function: discard overlay buffer
|
||||
status_t RELEASE_OVERLAY_BUFFER( const overlay_buffer *ob )
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
overlay_buffer_node *node;
|
||||
radeon_free_local_mem fm;
|
||||
status_t result;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
node = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer ));
|
||||
|
||||
if( si->active_overlay.on == node )
|
||||
Radeon_HideOverlay( ai );
|
||||
|
||||
// free memory
|
||||
fm.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
fm.handle = node->mem_handle;
|
||||
result = ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm );
|
||||
if( result != B_OK ) {
|
||||
SHOW_FLOW( 3, "ups - couldn't free memory (handle=%x, status=%s)",
|
||||
node->mem_handle, strerror( result ));
|
||||
}
|
||||
|
||||
ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
// remove from list
|
||||
if( node->next )
|
||||
node->next->prev = node->prev;
|
||||
|
||||
if( node->prev )
|
||||
node->prev->next = node->next;
|
||||
else
|
||||
vc->overlay_buffers = node->next;
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
|
||||
SHOW_FLOW0( 3, "success" );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// public function: get constraints of overlay unit
|
||||
status_t GET_OVERLAY_CONSTRAINTS( const display_mode *dm, const overlay_buffer *ob,
|
||||
overlay_constraints *oc )
|
||||
{
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
// probably, this is paranoia as we only get called by app_server
|
||||
// which should know what it's doing
|
||||
if( dm == NULL || ob == NULL || oc == NULL )
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// scaler input restrictions
|
||||
// TBD: check all these values; I reckon that
|
||||
// most of them are too restrictive
|
||||
|
||||
// position
|
||||
oc->view.h_alignment = 0;
|
||||
oc->view.v_alignment = 0;
|
||||
|
||||
// alignment
|
||||
switch (ob->space) {
|
||||
case B_RGB15:
|
||||
oc->view.width_alignment = 7;
|
||||
break;
|
||||
case B_RGB16:
|
||||
oc->view.width_alignment = 7;
|
||||
break;
|
||||
case B_RGB32:
|
||||
oc->view.width_alignment = 3;
|
||||
break;
|
||||
case B_YCbCr422:
|
||||
oc->view.width_alignment = 7;
|
||||
break;
|
||||
case B_YUV12:
|
||||
oc->view.width_alignment = 7;
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
oc->view.height_alignment = 0;
|
||||
|
||||
// size
|
||||
oc->view.width.min = 4; // make 4-tap filter happy
|
||||
oc->view.height.min = 4;
|
||||
oc->view.width.max = ob->width;
|
||||
oc->view.height.max = ob->height;
|
||||
|
||||
// scaler output restrictions
|
||||
oc->window.h_alignment = 0;
|
||||
oc->window.v_alignment = 0;
|
||||
oc->window.width_alignment = 0;
|
||||
oc->window.height_alignment = 0;
|
||||
oc->window.width.min = 2;
|
||||
oc->window.width.max = dm->virtual_width;
|
||||
oc->window.height.min = 2;
|
||||
oc->window.height.max = dm->virtual_height;
|
||||
|
||||
// TBD: these values need to be checked
|
||||
// (shamelessly copied from Matrix driver)
|
||||
oc->h_scale.min = 1.0f / (1 << 4);
|
||||
oc->h_scale.max = 1 << 12;
|
||||
oc->v_scale.min = 1.0f / (1 << 4);
|
||||
oc->v_scale.max = 1 << 12;
|
||||
|
||||
SHOW_FLOW0( 3, "success" );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// public function: allocate overlay unit
|
||||
overlay_token ALLOCATE_OVERLAY( void )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
virtual_card *vc = ai->vc;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
if( atomic_or( &si->overlay_mgr.inuse, 1 ) != 0 ) {
|
||||
SHOW_FLOW0( 3, "already in use" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SHOW_FLOW0( 3, "success" );
|
||||
|
||||
vc->uses_overlay = true;
|
||||
|
||||
return (void *)++si->overlay_mgr.token;
|
||||
}
|
||||
|
||||
|
||||
// public function: release overlay unit
|
||||
status_t RELEASE_OVERLAY(overlay_token ot)
|
||||
{
|
||||
virtual_card *vc = ai->vc;
|
||||
shared_info *si = ai->si;
|
||||
|
||||
SHOW_FLOW0( 3, "" );
|
||||
|
||||
if( (void *)si->overlay_mgr.token != ot )
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if( si->overlay_mgr.inuse == 0 )
|
||||
return B_ERROR;
|
||||
|
||||
if( si->active_overlay.on )
|
||||
Radeon_HideOverlay( ai );
|
||||
|
||||
si->overlay_mgr.inuse = 0;
|
||||
vc->uses_overlay = false;
|
||||
|
||||
SHOW_FLOW0( 3, "released" );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// public function: show/hide overlay
|
||||
status_t CONFIGURE_OVERLAY( overlay_token ot, const overlay_buffer *ob,
|
||||
const overlay_window *ow, const overlay_view *ov )
|
||||
{
|
||||
shared_info *si = ai->si;
|
||||
// virtual_card *vc = ai->vc;
|
||||
status_t result;
|
||||
|
||||
SHOW_FLOW0( 4, "" );
|
||||
|
||||
if( (uint32)ot != si->overlay_mgr.token )
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if( !si->overlay_mgr.inuse )
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if( ow == NULL || ov == NULL ) {
|
||||
SHOW_FLOW0( 3, "hide only" );
|
||||
Radeon_HideOverlay( ai );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if( ob == NULL )
|
||||
return B_ERROR;
|
||||
|
||||
ACQUIRE_BEN( si->engine.lock );
|
||||
|
||||
// store whished values
|
||||
si->pending_overlay.ot = ot;
|
||||
si->pending_overlay.ob = *ob;
|
||||
si->pending_overlay.ow = *ow;
|
||||
si->pending_overlay.ov = *ov;
|
||||
|
||||
si->pending_overlay.on = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer ));
|
||||
|
||||
result = Radeon_UpdateOverlay( ai );
|
||||
|
||||
RELEASE_BEN( si->engine.lock );
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Takes of PLL
|
||||
*/
|
||||
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
|
||||
#include "pll_regs.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
// read value "val" from PLL-register "addr"
|
||||
uint32 Radeon_INPLL( accelerator_info *ai, int addr )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
uint32 res;
|
||||
|
||||
OUTREG8( regs, RADEON_CLOCK_CNTL_INDEX, addr & 0x3f );
|
||||
res = INREG( regs, RADEON_CLOCK_CNTL_DATA );
|
||||
|
||||
R300_PLLFix( ai );
|
||||
return res;
|
||||
}
|
||||
|
||||
// write value "val" to PLL-register "addr"
|
||||
void Radeon_OUTPLL( accelerator_info *ai, uint8 addr, uint32 val )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
|
||||
OUTREG8( regs, RADEON_CLOCK_CNTL_INDEX, ((addr & 0x3f ) |
|
||||
RADEON_PLL_WR_EN));
|
||||
|
||||
OUTREG( regs, RADEON_CLOCK_CNTL_DATA, val );
|
||||
|
||||
// TBD: on XFree, there is no call of R300_PLLFix here,
|
||||
// though it should as we've accessed CLOCK_CNTL_INDEX
|
||||
//R300_PLLFix( ai );
|
||||
}
|
||||
|
||||
// write "val" to PLL-register "addr" keeping bits "mask"
|
||||
void Radeon_OUTPLLP( accelerator_info *ai, uint8 addr,
|
||||
uint32 val, uint32 mask )
|
||||
{
|
||||
uint32 tmp = Radeon_INPLL( ai, addr );
|
||||
tmp &= mask;
|
||||
tmp |= val;
|
||||
Radeon_OUTPLL( ai, addr, tmp );
|
||||
}
|
||||
|
||||
|
||||
static void Radeon_PLLWaitForReadUpdateComplete( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
int i;
|
||||
|
||||
// we should wait forever, but
|
||||
// 1. this is unsafe
|
||||
// 2. some r300 loop forever (reported by XFree86)
|
||||
for( i = 0; i < 10000; ++i ) {
|
||||
if( (Radeon_INPLL( ai, port->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV )
|
||||
& RADEON_PPLL_ATOMIC_UPDATE_R) == 0 )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void Radeon_PLLWriteUpdate( accelerator_info *ai, virtual_port *port )
|
||||
{
|
||||
Radeon_PLLWaitForReadUpdateComplete( ai, port );
|
||||
|
||||
Radeon_OUTPLLP( ai, port->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV,
|
||||
RADEON_PPLL_ATOMIC_UPDATE_W,
|
||||
~RADEON_PPLL_ATOMIC_UPDATE_W );
|
||||
}
|
||||
|
||||
// r300: to be called after each CLOCK_CNTL_INDEX access
|
||||
// (hardware bug fix suggested by XFree86)
|
||||
void R300_PLLFix( accelerator_info *ai )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
uint32 save, tmp;
|
||||
|
||||
if( ai->si->asic != rt_r300 )
|
||||
return;
|
||||
|
||||
save = INREG( regs, RADEON_CLOCK_CNTL_INDEX );
|
||||
tmp = save & ~(0x3f | RADEON_PLL_WR_EN);
|
||||
OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, tmp );
|
||||
tmp = INREG( regs, RADEON_CLOCK_CNTL_DATA );
|
||||
OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, save );
|
||||
}
|
||||
|
||||
|
||||
// table to map divider to register value
|
||||
typedef struct {
|
||||
int divider;
|
||||
int bitvalue;
|
||||
} post_div_entry;
|
||||
|
||||
static post_div_entry post_divs[] = {
|
||||
{ 1, 0 },
|
||||
{ 2, 1 },
|
||||
{ 4, 2 },
|
||||
{ 8, 3 },
|
||||
{ 3, 4 },
|
||||
{ 16, 5 },
|
||||
{ 6, 6 },
|
||||
{ 12, 7 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
// calculate PLL dividers (freq is in 10kHz)
|
||||
void Radeon_CalcPLLDividers( pll_info *pll, unsigned long freq, port_regs *values )
|
||||
{
|
||||
post_div_entry *post_div;
|
||||
|
||||
SHOW_FLOW( 2, "freq=%ld", freq );
|
||||
|
||||
// formula is for generated frequency is:
|
||||
// (ref_freq * feedback_div) / (ref_div * post_div )
|
||||
|
||||
// find proper divider by trial-and-error
|
||||
for( post_div = &post_divs[0]; post_div->divider; ++post_div ) {
|
||||
values->pll_output_freq = post_div->divider * freq;
|
||||
|
||||
if( values->pll_output_freq >= pll->min_pll_freq
|
||||
&& values->pll_output_freq <= pll->max_pll_freq )
|
||||
break;
|
||||
}
|
||||
|
||||
if( post_div->divider == 0 )
|
||||
SHOW_ERROR( 2, "Frequency (%d kHz) is out of PLL range!", freq );
|
||||
|
||||
values->dot_clock_freq = freq;
|
||||
values->feedback_div = RoundDiv( pll->ref_div * values->pll_output_freq,
|
||||
pll->ref_freq);
|
||||
values->post_div = post_div->divider;
|
||||
|
||||
values->ppll_ref_div = pll->ref_div;
|
||||
values->ppll_div_3 = (values->feedback_div | (post_div->bitvalue << 16));
|
||||
values->htotal_cntl = 0;
|
||||
|
||||
SHOW_FLOW( 2, "dot_clock_freq=%ld, pll_output_freq=%ld, ref_div=%d, feedback_div=%d, post_div=%d",
|
||||
values->dot_clock_freq, values->pll_output_freq,
|
||||
pll->ref_div, values->feedback_div, values->post_div );
|
||||
}
|
||||
|
||||
// write values into PLL registers
|
||||
void Radeon_ProgramPLL( accelerator_info *ai, virtual_port *port, port_regs *values )
|
||||
{
|
||||
vuint8 *regs = ai->regs;
|
||||
|
||||
SHOW_FLOW0( 2, "" );
|
||||
|
||||
// use some other PLL for pixel clock source to not fiddling with PLL
|
||||
// while somebody is using it
|
||||
Radeon_OUTPLLP( ai, port->is_crtc2 ? RADEON_PIXCLKS_CNTL : RADEON_VCLK_ECP_CNTL,
|
||||
RADEON_VCLK_SRC_CPU_CLK, ~RADEON_VCLK_SRC_SEL_MASK );
|
||||
|
||||
Radeon_OUTPLLP( ai,
|
||||
port->is_crtc2 ? RADEON_P2PLL_CNTL : RADEON_PPLL_CNTL,
|
||||
RADEON_PPLL_RESET
|
||||
| RADEON_PPLL_ATOMIC_UPDATE_EN
|
||||
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN,
|
||||
~(RADEON_PPLL_RESET
|
||||
| RADEON_PPLL_ATOMIC_UPDATE_EN
|
||||
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN) );
|
||||
|
||||
// select divider 3 (well, only required for first PLL)
|
||||
OUTREGP( regs, RADEON_CLOCK_CNTL_INDEX,
|
||||
RADEON_PLL_DIV_SEL_DIV3,
|
||||
~RADEON_PLL_DIV_SEL_MASK );
|
||||
|
||||
// probably this register doesn't need to be set as is not
|
||||
// touched by anyone (anyway - it doesn't hurt)
|
||||
Radeon_OUTPLLP( ai,
|
||||
port->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV,
|
||||
values->ppll_ref_div,
|
||||
~RADEON_PPLL_REF_DIV_MASK );
|
||||
|
||||
Radeon_OUTPLLP( ai,
|
||||
port->is_crtc2 ? RADEON_P2PLL_DIV_0 : RADEON_PPLL_DIV_3,
|
||||
values->ppll_div_3,
|
||||
~RADEON_PPLL_FB3_DIV_MASK );
|
||||
|
||||
Radeon_OUTPLLP( ai,
|
||||
port->is_crtc2 ? RADEON_P2PLL_DIV_0 : RADEON_PPLL_DIV_3,
|
||||
values->ppll_div_3,
|
||||
~RADEON_PPLL_POST3_DIV_MASK );
|
||||
|
||||
Radeon_PLLWriteUpdate( ai, port );
|
||||
Radeon_PLLWaitForReadUpdateComplete( ai, port );
|
||||
|
||||
Radeon_OUTPLL( ai,
|
||||
port->is_crtc2 ? RADEON_HTOTAL2_CNTL : RADEON_HTOTAL_CNTL,
|
||||
values->htotal_cntl );
|
||||
|
||||
Radeon_OUTPLLP( ai, port->is_crtc2 ? RADEON_P2PLL_CNTL : RADEON_PPLL_CNTL, 0,
|
||||
~(RADEON_PPLL_RESET
|
||||
| RADEON_PPLL_SLEEP
|
||||
| RADEON_PPLL_ATOMIC_UPDATE_EN
|
||||
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN) );
|
||||
|
||||
// there is no way to check whether PLL has settled, so wait a bit
|
||||
snooze( 5000 );
|
||||
|
||||
// use PLL for pixel clock again
|
||||
Radeon_OUTPLLP( ai, port->is_crtc2 ? RADEON_PIXCLKS_CNTL : RADEON_VCLK_ECP_CNTL,
|
||||
RADEON_VCLK_SRC_PPLL_CLK, ~RADEON_VCLK_SRC_SEL_MASK );
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2002/03, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Internal header file
|
||||
*/
|
||||
|
||||
#ifndef _RADEON_ACCELERANT_H
|
||||
#define _RADEON_ACCELERANT_H
|
||||
|
||||
|
||||
#include "radeon_interface.h"
|
||||
#include "accelerant_ext.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void _kdprintf_(const char *format, ...);
|
||||
//bool set_dprintf_enabled(bool); /* returns old enable flag */
|
||||
|
||||
#define dprintf _kdprintf_
|
||||
|
||||
extern int debug_level_flow;
|
||||
extern int debug_level_info;
|
||||
extern int debug_level_error;
|
||||
|
||||
#define DEBUG_MSG_PREFIX "Radeon - "
|
||||
|
||||
//#define DEBUG_MAX_LEVEL_FLOW 2
|
||||
|
||||
#include "debug_ext.h"
|
||||
|
||||
typedef struct accelerator_info {
|
||||
virtual_card *vc;
|
||||
vuint8 *regs; // pointer to mapped registers
|
||||
// !! dont't make it vuint32, access macros rely on 8 bits !!
|
||||
area_id shared_info_area;
|
||||
area_id regs_area;
|
||||
area_id virtual_card_area;
|
||||
int accelerant_is_clone;
|
||||
|
||||
int fd; // file descriptor of kernel driver
|
||||
struct log_info_t *log;
|
||||
|
||||
area_id mode_list_area; // cloned list of standard display modes
|
||||
display_mode *mode_list;
|
||||
shared_info *si;
|
||||
} accelerator_info;
|
||||
|
||||
|
||||
uint32 Radeon_RoundVWidth( int virtual_width, int bpp );
|
||||
uint16 Radeon_GetHSyncFudge( shared_info *si, physical_port *port, int datatype );
|
||||
void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode );
|
||||
bool Radeon_GetFormat( int space, int *format, int *bpp );
|
||||
status_t Radeon_CreateModeList( shared_info *si );
|
||||
|
||||
void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode );
|
||||
void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode );
|
||||
void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode );
|
||||
status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
|
||||
const display_mode *low, const display_mode *high, bool *isTunnel );
|
||||
bool Radeon_NeedsSecondPort( display_mode *mode );
|
||||
bool Radeon_DifferentPorts( display_mode *mode );
|
||||
|
||||
void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
|
||||
display_mode *mode, port_regs *values );
|
||||
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, virtual_port *port,
|
||||
port_regs *values );
|
||||
|
||||
void Radeon_CalcPLLDividers( pll_info *pll, unsigned long freq, port_regs *values );
|
||||
void Radeon_ProgramPLL( accelerator_info *ai, virtual_port *port, port_regs *values );
|
||||
|
||||
void Radeon_CalcFPRegisters( accelerator_info *ai, virtual_port *port, fp_info *fp_port, display_mode *mode, port_regs *values );
|
||||
void Radeon_ProgramFPRegisters( accelerator_info *ai, fp_info *fp_port, port_regs *values );
|
||||
status_t Radeon_ReadFPEDID( accelerator_info *ai, shared_info *si );
|
||||
|
||||
status_t Radeon_SetDPMS( accelerator_info *ai, virtual_port *port, int mode );
|
||||
uint32 Radeon_GetDPMS( accelerator_info *ai, virtual_port *port );
|
||||
|
||||
void Radeon_SetCursorColors( accelerator_info *ai, virtual_port *port );
|
||||
|
||||
void Radeon_Init2D( accelerator_info *ai, uint32 datatype );
|
||||
|
||||
int Radeon_WaitForIdle( accelerator_info *ai );
|
||||
void Radeon_ResetEngine( accelerator_info *ai );
|
||||
void Radeon_SendWaitUntilIdle( accelerator_info *ai );
|
||||
void Radeon_SendPurgeCache( accelerator_info *ai );
|
||||
void Radeon_WaitForFifo( accelerator_info *ai, int entries );
|
||||
void Radeon_Finish( accelerator_info *ai );
|
||||
|
||||
status_t Radeon_InitCP( accelerator_info *ai );
|
||||
void Radeon_SendCP( accelerator_info *ai, uint32 *buffer, uint32 num_dwords );
|
||||
void Radeon_WriteRegCP( accelerator_info *ai, uint32 reg, uint32 value );
|
||||
|
||||
void Radeon_ActivateVirtualCard( accelerator_info *ai );
|
||||
|
||||
void Radeon_ReadSettings( virtual_card *vc );
|
||||
void Radeon_WriteSettings( virtual_card *vc );
|
||||
|
||||
void Radeon_HideOverlay( accelerator_info *ai );
|
||||
status_t Radeon_UpdateOverlay( accelerator_info *ai );
|
||||
void Radeon_SetColourKey( accelerator_info *ai, const overlay_window *ow );
|
||||
|
||||
status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
Fast logger - application to write log file
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "log_dump.h"
|
||||
#include <OS.h>
|
||||
#include "radeon_interface.h"
|
||||
|
||||
|
||||
// usage: "radeonlog_dump device_name"
|
||||
// result gets written into "radeonlog" in home directory
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int device;
|
||||
uint32 size;
|
||||
char *buffer;
|
||||
status_t res;
|
||||
FILE *logfile;
|
||||
const char *logfile_name;
|
||||
|
||||
if( argc < 2 ) {
|
||||
fprintf( stderr, "radeonlog: missing device name\n" );
|
||||
return 3;
|
||||
}
|
||||
|
||||
device = open( argv[1], O_RDONLY );
|
||||
|
||||
if( device < 0 ) {
|
||||
fprintf( stderr, "radeonlog: cannot open log helper %s (%s)\n",
|
||||
argv[1], strerror( device ));
|
||||
return 3;
|
||||
}
|
||||
|
||||
logfile_name = "/boot/home/radeonlog";
|
||||
|
||||
logfile = fopen( logfile_name, "at" );
|
||||
|
||||
if( logfile == NULL ) {
|
||||
fprintf( stderr, "idelog: cannot open log file %s\n", logfile_name );
|
||||
return 3;
|
||||
}
|
||||
|
||||
if( (res = ioctl( device, RADEON_GET_LOG_SIZE, &size, sizeof( size ))) != B_OK ) {
|
||||
fprintf( stderr, "idelog: RADEON_GET_LOG_SIZE failed, %s\n", strerror( res ));
|
||||
return 3;
|
||||
}
|
||||
|
||||
fprintf( logfile, "buffer size: %ld\n", size );
|
||||
|
||||
buffer = malloc( size + sizeof( int32 ));
|
||||
((uint32*)buffer)[0] = size;
|
||||
|
||||
if( (res = ioctl( device, RADEON_GET_LOG_DATA, buffer, size )) != B_OK ) {
|
||||
fprintf( stderr, "idelog: RADEON_GET_LOG_DATA failed, %s\n", strerror( res ));
|
||||
return 3;
|
||||
}
|
||||
|
||||
log_printall( logfile, buffer, size );
|
||||
|
||||
fclose( logfile );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon accelerant
|
||||
|
||||
Settings file
|
||||
|
||||
We shouldn't really need settings as this info
|
||||
should be stored by app_server, but especially
|
||||
BWindowScreen programs cannot now about extra
|
||||
features/settings, so we need to store the flags
|
||||
internally (until I have a better idea ;)
|
||||
|
||||
Especially "SwapWindow" should be mode-independant
|
||||
(you don't swap monitors when you select another
|
||||
workspace, do you?)
|
||||
*/
|
||||
|
||||
#include "radeon_accelerant.h"
|
||||
#include "generic.h"
|
||||
#include "GlobalData.h"
|
||||
|
||||
#ifdef ENABLE_SETTINGS_FILE
|
||||
#include <FindDirectory.h>
|
||||
#include <Path.h>
|
||||
#include <File.h>
|
||||
#endif
|
||||
|
||||
void Radeon_ReadSettings( virtual_card *vc )
|
||||
{
|
||||
#ifdef ENABLE_SETTINGS_FILE
|
||||
BPath path;
|
||||
int32 tmp;
|
||||
|
||||
// per default we enable combine mode;
|
||||
// if actual mode isn't combine mode, we fall back to clone mode
|
||||
vc->wanted_multi_mode = mm_combine;
|
||||
vc->swapDisplays = false;
|
||||
|
||||
// per default, show overlay on first port
|
||||
//vc->whished_overlay_port = 0;
|
||||
|
||||
// this is problematic during boot: if there is multi-user support,
|
||||
// you don't have a user when app_server gets launched;
|
||||
// on the other hand, storing settings globally is not user-friendly...
|
||||
if( find_directory( B_USER_SETTINGS_DIRECTORY, &path ) != B_OK )
|
||||
return;
|
||||
|
||||
path.Append( "radeon" );
|
||||
|
||||
BFile file( path.Path(), B_READ_ONLY );
|
||||
|
||||
if( file.InitCheck() != B_OK )
|
||||
return;
|
||||
|
||||
BMessage settings;
|
||||
|
||||
if( settings.Unflatten( &file ) != B_OK )
|
||||
return;
|
||||
|
||||
if( settings.FindBool( "SwapDisplays", &vc->swapDisplays ) != B_OK )
|
||||
vc->swapDisplays = false;
|
||||
|
||||
if( settings.FindInt32( "MultiMonitorMode", &tmp ) != B_OK )
|
||||
tmp = mm_combine;
|
||||
|
||||
switch( tmp ) {
|
||||
case mm_none:
|
||||
case mm_mirror:
|
||||
case mm_combine:
|
||||
case mm_clone:
|
||||
vc->wanted_multi_mode = (multi_mode_e) tmp;
|
||||
break;
|
||||
default:
|
||||
vc->wanted_multi_mode = mm_combine;
|
||||
}
|
||||
|
||||
if( settings.FindInt32( "OverlayPort", &tmp ) != B_OK )
|
||||
tmp = 0;
|
||||
|
||||
//vc->whished_overlay_port = tmp;
|
||||
#else
|
||||
vc->wanted_multi_mode = mm_combine;
|
||||
vc->swapDisplays = false;
|
||||
vc->swapDisplays = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Radeon_WriteSettings( virtual_card *vc )
|
||||
{
|
||||
#ifdef ENABLE_SETTINGS_FILE
|
||||
BPath path;
|
||||
int32 tmp;
|
||||
|
||||
// this is problematic during boot: if there is multi-user support,
|
||||
// you don't have a user when app_server gets launched;
|
||||
// on the other hand, storing settings globally is not user-friendly...
|
||||
if( find_directory( B_USER_SETTINGS_DIRECTORY, &path ) != B_OK )
|
||||
return;
|
||||
|
||||
path.Append( "radeon" );
|
||||
|
||||
BFile file( path.Path(), B_CREATE_FILE | B_WRITE_ONLY );
|
||||
|
||||
if( file.InitCheck() != B_OK )
|
||||
return;
|
||||
|
||||
BMessage settings;
|
||||
|
||||
settings.AddBool( "SwapDisplays", vc->swapDisplays );
|
||||
tmp = vc->wanted_multi_mode;
|
||||
settings.AddInt32( "MultiMonitorMode", tmp );
|
||||
/*tmp = vc->whished_overlay_port;
|
||||
settings.AddInt32( "OverlayPort", tmp );*/
|
||||
|
||||
settings.Flatten( &file );
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (c) 2003, Thomas Kurschel
|
||||
|
||||
|
||||
Part of DDC driver
|
||||
|
||||
Test program, using Radeon Kernel Driver for I2C access.
|
||||
|
||||
!DANGER! You can specify _any_ io-port to use for i2c
|
||||
transfer - this is a good way to mess up your hardware.
|
||||
Usual addresses are 96, 100, 104 and 108.
|
||||
You've been warned.
|
||||
*/
|
||||
|
||||
#include "ddc.h"
|
||||
#include "radeon_interface.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <KernelExport.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
status_t get_signals( void *cookie, int *clk, int *data );
|
||||
status_t set_signals( void *cookie, int clk, int data );
|
||||
|
||||
int io_port;
|
||||
|
||||
status_t get_signals( void *cookie, int *clk, int *data )
|
||||
{
|
||||
int fd = (int)cookie;
|
||||
radeon_getset_i2c buffer;
|
||||
status_t res;
|
||||
|
||||
buffer.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
buffer.port = io_port;
|
||||
|
||||
res = ioctl( fd, RADEON_GET_I2C_SIGNALS, &buffer, sizeof( buffer ));
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
*clk = (buffer.value >> 9) & 1;
|
||||
*data = (buffer.value >> 8) & 1;
|
||||
|
||||
//printf( "read: %i, %i\n", *clk, *data );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
bigtime_t max_time = 0;
|
||||
bigtime_t old_time;
|
||||
|
||||
status_t set_signals( void *cookie, int clk, int data )
|
||||
{
|
||||
int fd = (int)cookie;
|
||||
radeon_getset_i2c buffer;
|
||||
status_t res;
|
||||
bigtime_t new_time;
|
||||
|
||||
old_time = system_time();
|
||||
|
||||
buffer.magic = RADEON_PRIVATE_DATA_MAGIC;
|
||||
buffer.port = io_port;
|
||||
|
||||
res = ioctl( fd, RADEON_GET_I2C_SIGNALS, &buffer, sizeof( buffer ));
|
||||
if( res != B_OK )
|
||||
return res;
|
||||
|
||||
buffer.value &= ~((1 << 1) | (1 << 0));
|
||||
buffer.value &= ~((1 << 16) | (1 << 17));
|
||||
buffer.value |= ((1-clk) << 17) | ((1-data) << 16);
|
||||
//buffer.value |= (1 << 16) | (1 <<17 );
|
||||
|
||||
//printf( "write: %i, %i\n", clk, data );
|
||||
new_time = system_time();
|
||||
max_time = max( max_time, new_time - old_time );
|
||||
|
||||
old_time = new_time;
|
||||
|
||||
|
||||
return ioctl( fd, RADEON_SET_I2C_SIGNALS, &buffer, sizeof( buffer ));
|
||||
}
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
int fd;
|
||||
i2c_bus bus;
|
||||
status_t res;
|
||||
edid1_info edid;
|
||||
void *vdif;
|
||||
size_t vdif_len;
|
||||
char *name = argv[1];
|
||||
|
||||
if( argc < 3 ) {
|
||||
fprintf( stderr, "usage: test_ddc driver_name io_port\n" );
|
||||
return 2;
|
||||
}
|
||||
|
||||
//name = "/dev/graphics/1002_4c59_010000";
|
||||
|
||||
fd = open( name, O_RDWR );
|
||||
if( fd < 0 ) {
|
||||
fprintf( stderr, "Cannot open device %s\n", argv[1] );
|
||||
return 3;
|
||||
}
|
||||
|
||||
io_port = atoi( argv[2] );
|
||||
|
||||
fprintf( stderr, "io-port: %x\n", io_port );
|
||||
|
||||
bus.cookie = (void *)fd;
|
||||
bus.set_signals = &set_signals;
|
||||
bus.get_signals = &get_signals;
|
||||
|
||||
old_time = system_time();
|
||||
|
||||
res = ddc2_read_edid1( &bus, &edid, &vdif, &vdif_len );
|
||||
if( res < 0 ) {
|
||||
printf( "%i", (int)max_time );
|
||||
fprintf( stderr, "Error reading edid: %s\n", strerror( res ));
|
||||
return 1;
|
||||
}
|
||||
|
||||
edid_dump( &edid );
|
||||
|
||||
fprintf( stderr, "success\n" );
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright (c) 2002, Thomas Kurschel
|
||||
|
||||
|
||||
Part of Radeon driver
|
||||
|
||||
some utility functions
|
||||
*/
|
||||
|
||||
#include "OS.h"
|
||||
#include "utils.h"
|
||||
|
||||
// get ceil( log2( size ))
|
||||
int log2( uint32 x )
|
||||
{
|
||||
int res;
|
||||
uint32 tmp;
|
||||
|
||||
for( res = 0, tmp = x ; tmp > 1 ; ++res )
|
||||
tmp >>= 1;
|
||||
|
||||
if( (x & ((1 << res) - 1)) != 0 )
|
||||
++res;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef _UTILS_H
|
||||
#define _UTILS_H
|
||||
|
||||
extern int log2( uint32 x );
|
||||
|
||||
static inline int RoundDiv( int num, int den )
|
||||
{
|
||||
return (num + (den / 2)) / den;
|
||||
}
|
||||
|
||||
static inline int ceilShiftDiv( int num, int shift )
|
||||
{
|
||||
return (num + (1 << shift) - 1) >> shift;
|
||||
}
|
||||
|
||||
static inline int ceilDiv( int num, int den )
|
||||
{
|
||||
return (num + den - 1) / den;
|
||||
}
|
||||
|
||||
// macros for fix-point calculation
|
||||
#define FIX_SHIFT 32
|
||||
#define FIX_SCALE (1LL << FIX_SHIFT)
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user