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:
shadow303
2004-03-15 00:58:55 +00:00
parent 3bba0ebe0a
commit 409f1731e2
43 changed files with 8691 additions and 0 deletions
@@ -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;
}
+296
View File
@@ -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
+250
View File
@@ -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;
}
+40
View File
@@ -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] );
}
+179
View File
@@ -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;
}
+160
View File
@@ -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;
}
+21
View File
@@ -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
+23
View File
@@ -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"
+242
View File
@@ -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;
}
+152
View File
@@ -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; }
}
}
}
+220
View File
@@ -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 );
}
+146
View File
@@ -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
+278
View File
@@ -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;
}
+273
View File
@@ -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;
}
+63
View File
@@ -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
+422
View File
@@ -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;
}
+69
View File
@@ -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
+129
View File
@@ -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
+76
View File
@@ -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
+75
View File
@@ -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 );
}
}
+17
View File
@@ -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
+18
View File
@@ -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",
};
+242
View File
@@ -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;
}
+213
View File
@@ -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;
}
+119
View File
@@ -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
}
+127
View File
@@ -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;
}
+26
View File
@@ -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;
}
+25
View File
@@ -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