Upgrade to version 4.1 of radeon driver.

Includes some common routines which can be used by other accelerants.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8406 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shadow303
2004-07-16 00:48:12 +00:00
parent 8f6c61bcef
commit 2a37e4c1cf
49 changed files with 4080 additions and 3558 deletions
+1
View File
@@ -1,5 +1,6 @@
SubDir OBOS_TOP src add-ons accelerants ;
SubInclude OBOS_TOP src add-ons accelerants common ;
SubInclude OBOS_TOP src add-ons accelerants matrox ;
SubInclude OBOS_TOP src add-ons accelerants neomagic ;
SubInclude OBOS_TOP src add-ons accelerants nvidia ;
+12
View File
@@ -0,0 +1,12 @@
SubDir OBOS_TOP src add-ons accelerants common ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics radeon ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
StaticLibrary accelerantscommon :
ddc.c
decode_edid.c
dump_edid.c
i2c.c
;
@@ -11,14 +11,13 @@
#include <KernelExport.h>
#include <stdlib.h>
#include "ddc_int.h"
#include "edid.h"
#include "ddc.h"
#include "i2c.h"
// number of retries to read ddc data
#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 )
@@ -27,21 +26,18 @@ static status_t verify_checksum( const uint8 *data, size_t len )
uint8 sum = 0;
uint8 all_or = 0;
for( i = 0; i < (int)len; ++i, ++data ) {
for( i = 0; i < 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" );
SHOW_ERROR0( 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" );
SHOW_ERROR0( 2, "Checksum error of DDC information" );
return B_IO_ERROR;
}
@@ -54,7 +50,7 @@ static status_t ddc2_read( const i2c_bus *bus, int start, uint8 *buffer, size_t
uint8 write_buffer[2];
i2c_timing timing;
int i;
status_t res = B_ERROR;
status_t res;
write_buffer[0] = start & 0xff;
write_buffer[1] = (start >> 8) & 0xff;
@@ -71,7 +67,8 @@ static status_t ddc2_read( const i2c_bus *bus, int start, uint8 *buffer, size_t
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 )
// don't verify checksum - it's often broken
if( res == B_OK /*&& verify_checksum( buffer, len ) == B_OK*/ )
break;
res = B_ERROR;
@@ -128,17 +125,6 @@ status_t ddc2_read_edid1( const i2c_bus *bus, edid1_info *edid,
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;
@@ -4,7 +4,10 @@
Part of DDC driver
EDID handling.
EDID decoder.
The EDID information is tightly packed; this file takes care of
converting it to a usable structure.
*/
#include "edid.h"
@@ -131,7 +134,7 @@ static void copy_str( char *dest, const uint8 *src, size_t len )
int i;
// copy until 0xa
for( i = 0; i < (int)len; ++i ) {
for( i = 0; i < len; ++i ) {
if( src[i] == 0xa )
break;
@@ -62,7 +62,7 @@ static status_t send_start_condition( const i2c_bus *bus, const i2c_timing *timi
res = wait_for_clk( bus, timing, timing->start_timeout );
if( res != B_OK ) {
SHOW_FLOW0( 2, "Timeout sending start condition" );
SHOW_FLOW0( 3, "Timeout sending start condition" );
return res;
}
@@ -89,7 +89,7 @@ static status_t send_stop_condition( const i2c_bus *bus, const i2c_timing *timin
// 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" );
SHOW_FLOW0( 3, "Timeout sending stop condition" );
return res;
}
@@ -116,7 +116,7 @@ static status_t send_bit( const i2c_bus *bus, const i2c_timing *timing, bool bit
res = wait_for_clk( bus, timing, timeout );
if( res != B_OK ) {
SHOW_FLOW0( 2, "Timeout when sending next bit" );
SHOW_FLOW0( 3, "Timeout when sending next bit" );
return res;
}
@@ -141,7 +141,7 @@ static status_t send_acknowledge( const i2c_bus *bus, const i2c_timing *timing )
res = wait_for_clk( bus, timing, timing->ack_start_timeout );
if( res != B_OK ) {
SHOW_FLOW0( 2, "Timeout when sending acknowledge" );
SHOW_FLOW0( 3, "Timeout when sending acknowledge" );
return res;
}
@@ -158,7 +158,7 @@ static status_t send_acknowledge( const i2c_bus *bus, const i2c_timing *timing )
break;
if( system_time() - start_time > timing->ack_timeout ) {
SHOW_FLOW0( 2, "Slave didn't acknowledge byte" );
SHOW_FLOW0( 3, "Slave didn't acknowledge byte" );
return B_TIMEOUT;
}
@@ -183,7 +183,7 @@ static status_t send_byte( const i2c_bus *bus, const i2c_timing *timing,
{
int i;
SHOW_FLOW( 2, "%x ", byte );
SHOW_FLOW( 3, "%x ", byte );
for( i = 7; i >= 0; --i ) {
status_t res;
@@ -243,7 +243,7 @@ static status_t receive_bit( const i2c_bus *bus, const i2c_timing *timing,
// 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" );
SHOW_FLOW0( 3, "Timeout waiting for bit sent by slave" );
return res;
}
@@ -361,7 +361,7 @@ status_t i2c_send_receive( const i2c_bus *bus, const i2c_timing *timing,
return res;
err:
SHOW_FLOW0( 2, "Cancelling transmission" );
SHOW_FLOW0( 3, "Cancelling transmission" );
send_stop_condition( bus, timing );
return res;
}
+167 -169
View File
@@ -11,18 +11,12 @@
#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"
#include "CP.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
@@ -30,38 +24,32 @@
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;
}
(void)et;
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);
while( count > 0 ) {
uint32 sub_count;
START_IB();
WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_BITBLT_MULTI, count,
INDIRECT_BUFFER_SIZE, 3, 2 );
*buffer++ = 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 + 3 > PACKET_BUFFER_LEN ) {
buffer[0] |= (offset - 2) << 16;
Radeon_SendCP( ai, buffer, offset );
offset = 0;
for( ; sub_count > 0; --sub_count, ++list ) {
*buffer++ = (list->src_left << 16) | list->src_top;
*buffer++ = (list->dest_left << 16) | list->dest_top;
*buffer++ = ((list->width + 1) << 16) | (list->height + 1);
}
}
if( offset > 0 ) {
buffer[0] |= (offset - 2) << 16;
Radeon_SendCP( ai, buffer, offset );
SUBMIT_IB_VC();
}
++ai->si->engine.count;
@@ -77,41 +65,35 @@ 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
(void)et;
while( count > 0 ) {
uint32 sub_count;
START_IB();
WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_PAINT_MULTI, count,
INDIRECT_BUFFER_SIZE, 2, 3 );
*buffer++ = RADEON_GMC_BRUSH_SOLID_COLOR
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
| RADEON_GMC_SRC_DATATYPE_COLOR
| RADEON_ROP3_P;
buffer[offset++] = colorIndex;
*buffer++ = colorIndex;
for( ; sub_count > 0; --sub_count, ++list ) {
*buffer++ = (list->left << 16) | list->top;
*buffer++ =
((list->right - list->left + 1) << 16) |
(list->bottom - list->top + 1);
}
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;
}
SUBMIT_IB_VC();
}
if( offset > 0 ) {
buffer[0] |= (offset - 2) << 16;
Radeon_SendCP( ai, buffer, offset );
}
++ai->si->engine.count;
}
@@ -123,54 +105,49 @@ void FILL_RECTANGLE(engine_token *et, uint32 colorIndex,
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;
(void)et;
while( count > 0 ) {
uint32 sub_count;
START_IB();
// take core to leave space for ROP reset!
WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_PAINT_MULTI, count,
INDIRECT_BUFFER_SIZE - 2, 2, 2 );
*buffer++ = RADEON_GMC_BRUSH_NONE
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
| RADEON_GMC_SRC_DATATYPE_COLOR
| RADEON_ROP3_Dn;
for( ; sub_count > 0; --sub_count, ++list ) {
*buffer++ = (list->left << 16) | list->top;
*buffer++ =
((list->right - list->left + 1) << 16) |
(list->bottom - list->top + 1);
}
// 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++ = CP_PACKET0( RADEON_DP_GUI_MASTER_CNTL, 1 );
*buffer++ = 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->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;
}
SUBMIT_IB_VC();
}
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;
}
@@ -182,68 +159,86 @@ void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count)
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;
(void)et;
buffer[offset++] = (x << 16) | y;
buffer[offset++] = (width << 16) | 1;
while( count > 0 ) {
uint32 sub_count;
if( offset + 2 > PACKET_BUFFER_LEN ) {
buffer[0] |= (offset - 2) << 16;
START_IB();
Radeon_SendCP( ai, buffer, offset );
offset = 0;
}
}
WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_PAINT_MULTI, count,
INDIRECT_BUFFER_SIZE , 2, 3 );
*buffer++ = RADEON_GMC_BRUSH_SOLID_COLOR
| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
| RADEON_GMC_SRC_DATATYPE_COLOR
| RADEON_ROP3_P;
*buffer++ = colorIndex;
for( ; sub_count > 0; --sub_count ) {
uint16 y, x, width;
if( offset > 0 ) {
buffer[0] |= (offset - 2) << 16;
Radeon_SendCP( ai, buffer, offset );
}
y = *list++;
x = *list++;
width = *list++ - x + 1;
*buffer++ = (x << 16) | y;
*buffer++ = (width << 16) | 1;
}
SUBMIT_IB_VC();
}
++ai->si->engine.count;
}
// prepare 2D acceleration
void Radeon_Init2D( accelerator_info *ai, uint32 datatype )
void Radeon_Init2D( accelerator_info *ai )
{
SHOW_FLOW0( 3, "" );
// forget about 3D
OUTREG( ai->regs, RADEON_RB3D_CNTL, 0 );
START_IB();
//Radeon_ResetEngine( ai );
// forget about 3D
WRITE_IB_REG( RADEON_RB3D_CNTL, 0 );
SUBMIT_IB();
}
// fill state buffer that sets 2D registers up for accelerated operations
void Radeon_FillStateBuffer( accelerator_info *ai, uint32 datatype )
{
virtual_card *vc = ai->vc;
uint32 pitch_offset;
uint32 *buffer, *buffer_start;
SHOW_FLOW0( 4, "" );
// make sure buffer is not used
Radeon_InvalidateStateBuffer( ai, vc->state_buffer_idx );
buffer = buffer_start = Radeon_GetIndirectBufferPtr( ai, vc->state_buffer_idx );
// set offset of frame buffer and pitch
pitch_offset =
((ai->si->memory[mt_local].virtual_addr_start + vc->fb_offset) >> 10) |
((vc->pitch >> 6) << 22);
WRITE_IB_REG( RADEON_DEFAULT_OFFSET, pitch_offset );
WRITE_IB_REG( RADEON_DST_PITCH_OFFSET, pitch_offset );
WRITE_IB_REG( RADEON_SRC_PITCH_OFFSET, pitch_offset );
// no siccors
Radeon_WaitForFifo( ai, 1 );
OUTREG( ai->regs, RADEON_DEFAULT_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX
| RADEON_DEFAULT_SC_BOTTOM_MAX));
WRITE_IB_REG( 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,
WRITE_IB_REG( RADEON_DP_GUI_MASTER_CNTL,
(datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
| RADEON_GMC_CLR_CMP_CNTL_DIS
@@ -257,37 +252,40 @@ void Radeon_Init2D( accelerator_info *ai, uint32 datatype )
// 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 );
}
WRITE_IB_REG( RADEON_DST_LINE_START, 0);
WRITE_IB_REG( RADEON_DST_LINE_END, 0);
WRITE_IB_REG( RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff);
WRITE_IB_REG( RADEON_DP_BRUSH_BKGD_CLR, 0x00000000);
WRITE_IB_REG( RADEON_DP_SRC_FRGD_CLR, 0xffffffff);
WRITE_IB_REG( RADEON_DP_SRC_BKGD_CLR, 0x00000000);
WRITE_IB_REG( RADEON_DP_WRITE_MASK, 0xffffffff);
// 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 );
vc->state_buffer_size = buffer - buffer_start;
ai->si->active_vc = vc->id;
}
// allocate indirect buffer to contain state of virtual card
void Radeon_AllocateVirtualCardStateBuffer( accelerator_info *ai )
{
virtual_card *vc = ai->vc;
vc->state_buffer_idx = Radeon_AllocIndirectBuffer( ai, false );
// mark as being unused
vc->state_buffer_size = -1;
}
// free indirect buffer containing state of virtual card
void Radeon_FreeVirtualCardStateBuffer( accelerator_info *ai )
{
virtual_card *vc = ai->vc;
// make sure it's not used anymore
Radeon_InvalidateStateBuffer( ai, vc->state_buffer_idx );
// get rid of it
Radeon_FreeIndirectBuffer( ai, vc->state_buffer_idx, false );
}
+345 -236
View File
@@ -5,292 +5,401 @@
Part of Radeon accelerant
Command Processor handling
Something about synchronization in general:
The DDK says that only some register accesses are stored in the
Command FIFO, i.e. in almost all cases you don't have to wait until
there is enough space in this FIFO. Unfortunately, ATI doesn't speak
clearly here and doesn't tell you which registers are buffered and
which not (the r300 DDK provides some examples only, other DDKs refer
to some include file where no such info could be found).
Looking at pre-Radeon specs, we have the following register ranges:
0 configuration/display/multi-media registers
0xf00 read-only PCI configuration space
0x1000 CCE registers
0x1400 FIFOed GUI-registers
So, if the list is still correct, the affected registers are only
those used for 2D/3D drawing.
This is very important as if the register you want to write is
buffered, you have to do a busy wait until there is enough FIFO
space. As concurrent threads may do the same, register access should
only be done with a lock held. We never write GUI-registers directly,
so we never have to wait for the FIFO and thus don't need this lock.
*/
#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 "CP.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 )
static uint getAvailRingBuffer( accelerator_info *ai )
{
shared_info *si = ai->si;
CP_info *cp = &ai->si->cp;
int space;
// space = *si->ring.head - si->ring.tail;
space = INREG( ai->regs, RADEON_CP_RB_RPTR ) - si->ring.tail;
space =
*(uint32 *)(ai->mapped_memory[cp->feedback.mem_type].data + cp->feedback.head_mem_offset)
//*cp->ring.head
- cp->ring.tail;
//space = INREG( ai->regs, RADEON_CP_RB_RPTR ) - cp->ring.tail;
if( space <= 0 )
space += si->ring.size;
space += cp->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 );
SHOW_FLOW( 3, "head=%ld, tail=%ld, space=%ld",
*(uint32 *)(ai->mapped_memory[cp->feedback.mem_type].data + cp->feedback.head_mem_offset),
//*cp->ring.head,
cp->ring.tail, space );
LOG1( si->log, _GetAvailRingBufferQueue, space );
cp->ring.space = 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;
// mark all indirect buffers that have been processed as being free;
// lock must be hold
void Radeon_FreeIndirectBuffers( accelerator_info *ai )
{
CP_info *cp = &ai->si->cp;
int32 cur_processed_tag =
((uint32 *)(ai->mapped_memory[cp->feedback.mem_type].data + cp->feedback.scratch_mem_offset))[1];
//ai->si->cp.scratch.ptr[1];
//INREG( ai->regs, RADEON_SCRATCH_REG1 );
SHOW_FLOW( 3, "processed_tag=%d", cur_processed_tag );
// mark all sent indirect buffers as free
while( cp->buffers.oldest != -1 ) {
indirect_buffer *oldest_buffer =
&cp->buffers.buffers[cp->buffers.oldest];
int tmp_oldest_buffer;
SHOW_FLOW( 3, "oldset buffer's tag: %d", oldest_buffer->send_tag );
// this is a tricky calculation to handle wrap-arounds correctly,
// so don't change it unless you really understand the signess problem
if( (int32)(cur_processed_tag - oldest_buffer->send_tag) < 0 )
break;
SHOW_FLOW( 3, "mark %d as being free", oldest_buffer->send_tag );
// remove buffer from "used" list
tmp_oldest_buffer = oldest_buffer->next;
if( tmp_oldest_buffer == -1 )
cp->buffers.newest = -1;
// put it on free list
oldest_buffer->next = cp->buffers.free_list;
cp->buffers.free_list = cp->buffers.oldest;
cp->buffers.oldest = tmp_oldest_buffer;
}
}
// wait until an indirect buffer becomes available;
// lock must be hold
void Radeon_WaitForFreeIndirectBuffers( accelerator_info *ai )
{
bigtime_t start_time;
CP_info *cp = &ai->si->cp;
SHOW_FLOW0( 3, "" );
// init raw CP
loadMicroEngineRAMData( ai );
start_time = system_time();
// 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;
while( 1 ) {
bigtime_t sample_time;
space = getAvailRingBuffer( ai );
Radeon_FreeIndirectBuffers( ai );
if( space == 0 )
continue;
if( cp->buffers.free_list >= 0 )
return;
sample_time = system_time();
if( sample_time - start_time > 100000 )
break;
max_copy = min( space, num_dwords );
RELEASE_BEN( cp->lock );
#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;
// use exponential fall-off
// in the beginning do busy-waiting, later on we let the thread sleep;
// the micro-spin is used to reduce PCI load
if( sample_time - start_time > 5000 )
snooze( (sample_time - start_time) / 10 );
else
si->ring.tail = 0;
Radeon_Spin( 1 );
ACQUIRE_BEN( cp->lock );
}
// 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
SHOW_ERROR0( 0, "All buffers are in use and engine doesn't finish any of them" );
// lock must be released during reset (reset acquires it automatically)
RELEASE_BEN( cp->lock );
Radeon_ResetEngine( ai );
ACQUIRE_BEN( cp->lock );
}
// allocate an indirect buffer
int Radeon_AllocIndirectBuffer( accelerator_info *ai, bool keep_lock )
{
CP_info *cp = &ai->si->cp;
int buffer_idx;
// flush writes to ring
SHOW_FLOW0( 3, "" );
ACQUIRE_BEN( cp->lock );
if( cp->buffers.free_list == -1 )
Radeon_WaitForFreeIndirectBuffers( ai );
buffer_idx = cp->buffers.free_list;
cp->buffers.free_list = cp->buffers.buffers[buffer_idx].next;
//if( !keep_lock )
RELEASE_BEN( cp->lock );
(void)keep_lock;
SHOW_FLOW( 3, "got %d", buffer_idx );
return buffer_idx;
}
// explicitely free an indirect buffer;
// this is not needed if the buffer was send via SendIndirectBuffer()
// never_used - set to true if the buffer wasn't even sent indirectly
// as a state buffer
// !Warning!
// if never_used is false, execution may take very long as all buffers
// must be flushed!
void Radeon_FreeIndirectBuffer( accelerator_info *ai, int buffer_idx, bool never_used )
{
CP_info *cp = &ai->si->cp;
SHOW_FLOW( 3, "buffer_idx=%d, never_used=%d", buffer_idx, never_used );
// if the buffer was used as a state buffer, we don't record its usage,
// so we don't know if the buffer was/is/will be used;
// the only way to be sure is to let the CP run dry
if( !never_used )
Radeon_WaitForIdle( ai, false );
ACQUIRE_BEN( cp->lock );
cp->buffers.buffers[buffer_idx].next = cp->buffers.free_list;
cp->buffers.free_list = buffer_idx;
RELEASE_BEN( cp->lock );
SHOW_FLOW0( 3, "done" );
}
// this function must be moved to end of file to avoid inlining
void Radeon_WaitForRingBufferSpace( accelerator_info *ai, uint num_dwords );
// start writing to ring buffer
// num_dwords - number of dwords to write (must be precise!)
// !Warning!
// during wait, CP's benaphore is released
#define WRITE_RB_START( num_dwords ) \
{ \
uint32 *ring_start; \
uint32 ring_tail, ring_tail_mask; \
uint32 ring_tail_increment = (num_dwords); \
if( cp->ring.space < ring_tail_increment ) \
Radeon_WaitForRingBufferSpace( ai, ring_tail_increment ); \
ring_start = \
(uint32 *)(ai->mapped_memory[cp->ring.mem_type].data + cp->ring.mem_offset); \
/*cp->ring.start;*/ \
ring_tail = cp->ring.tail; \
ring_tail_mask = cp->ring.tail_mask;
// write single dword to ring buffer
#define WRITE_RB( value ) \
{ \
uint32 val = (value); \
SHOW_FLOW( 3, "@%d: %x", ring_tail, val ); \
ring_start[ring_tail++] = val; \
ring_tail &= ring_tail_mask; \
}
// finish writing to ring buffer
#define WRITE_RB_FINISH \
cp->ring.tail = ring_tail; \
cp->ring.space -= ring_tail_increment; \
}
// submit indirect buffer for execution.
// the indirect buffer must not be used afterwards!
// buffer_idx - index of indirect buffer to submit
// buffer_size - size of indirect buffer in 32 bits
// state_buffer_idx - index of indirect buffer to restore required state
// state_buffer_size - size of indirect buffer to restore required state
// returns: tag of buffer (so you can wait for its execution)
// if no special state is required, set state_buffer_size to zero
void Radeon_SendIndirectBuffer( accelerator_info *ai,
int buffer_idx, int buffer_size,
int state_buffer_idx, int state_buffer_size, bool has_lock )
{
CP_info *cp = &ai->si->cp;
bool need_stateupdate;
SHOW_FLOW( 3, "buffer_idx=%d, buffer_size=%d, state_buffer_idx=%d, state_buffer_size=%d",
buffer_idx, buffer_size, state_buffer_idx, state_buffer_size );
if( (buffer_size & 1) != 0 ) {
SHOW_FLOW( 3, "buffer has uneven size (%d)", buffer_size );
// size of indirect buffers _must_ be multiple of 64 bits, so
// add a nop to fulfil alignment
Radeon_GetIndirectBufferPtr( ai, buffer_idx )[buffer_size] = RADEON_CP_PACKET2;
buffer_size += 1;
}
//if( !has_lock )
ACQUIRE_BEN( cp->lock );
(void)has_lock;
need_stateupdate =
state_buffer_size > 0 && state_buffer_idx != cp->buffers.active_state;
WRITE_RB_START( 5 + (need_stateupdate ? 3 : 0) );
// if the indirect buffer to submit requires a special state and the
// hardware is in wrong state then execute state buffer
if( need_stateupdate ) {
SHOW_FLOW0( 3, "update state" );
WRITE_RB( CP_PACKET0( RADEON_CP_IB_BASE, 2 ));
WRITE_RB( cp->buffers.vm_start +
state_buffer_idx * INDIRECT_BUFFER_SIZE * sizeof( uint32 ));
WRITE_RB( state_buffer_size );
cp->buffers.active_state = state_buffer_idx;
}
// execute indirect buffer
WRITE_RB( CP_PACKET0( RADEON_CP_IB_BASE, 2 ));
WRITE_RB( cp->buffers.vm_start + buffer_idx * INDIRECT_BUFFER_SIZE * sizeof( uint32 ));
WRITE_RB( buffer_size );
// give buffer a tag so it can be freed after execution
WRITE_RB( CP_PACKET0( RADEON_SCRATCH_REG1, 1 ));
WRITE_RB( cp->buffers.buffers[buffer_idx].send_tag = (int32)++cp->buffers.cur_tag );
SHOW_FLOW( 3, "Assigned tag %d", cp->buffers.buffers[buffer_idx].send_tag );
WRITE_RB_FINISH;
// append buffer to list of submitted buffers
if( cp->buffers.newest > 0 )
cp->buffers.buffers[cp->buffers.newest].next = buffer_idx;
else
cp->buffers.oldest = buffer_idx;
cp->buffers.newest = buffer_idx;
cp->buffers.buffers[buffer_idx].next = -1;
// flush writes to CP buffers
// (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
// make sure the motherboard chipset has flushed its write buffer by
// reading some uncached memory
(void)*si->ring.head;
//(void)*(volatile int *)si->framebuffer;
INREG( ai->regs, RADEON_CP_RB_RPTR );
//SHOW_FLOW( 3, "new tail: %d", cp->ring.tail );
//snooze( 100 );
// 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 );
OUTREG( ai->regs, RADEON_CP_RB_WPTR, cp->ring.tail );
// read from PCI bus to ensure correct posting
INREG( ai->regs, RADEON_CP_RB_RPTR );
//INREG( ai->regs, RADEON_CP_RB_RPTR );
RELEASE_BEN( cp->lock );
SHOW_FLOW0( 3, "done" );
}
// mark state buffer as being invalid;
// this must be done _before_ modifying the state buffer as the
// state buffer may be in use
void Radeon_InvalidateStateBuffer( accelerator_info *ai, int state_buffer_idx )
{
CP_info *cp = &ai->si->cp;
// make sure state buffer is not used anymore
Radeon_WaitForIdle( ai, false );
ACQUIRE_BEN( cp->lock );
// mark state as being invalid
if( cp->buffers.active_state == state_buffer_idx )
cp->buffers.active_state = -1;
RELEASE_BEN( cp->lock );
}
// wait until there is enough space in ring buffer
// num_dwords - number of dwords needed in ring buffer
// must be called with benaphore hold
void Radeon_WaitForRingBufferSpace( accelerator_info *ai, uint num_dwords )
{
bigtime_t start_time;
CP_info *cp = &ai->si->cp;
start_time = system_time();
while( getAvailRingBuffer( ai ) < num_dwords ) {
bigtime_t sample_time;
sample_time = system_time();
if( sample_time - start_time > 100000 )
break;
RELEASE_BEN( cp->lock );
// use exponential fall-off
// in the beginning do busy-waiting, later on we let the thread sleep;
// the micro-spin is used to reduce PCI load
if( sample_time - start_time > 5000 )
snooze( (sample_time - start_time) / 10 );
else
Radeon_Spin( 1 );
ACQUIRE_BEN( cp->lock );
}
}
+119
View File
@@ -0,0 +1,119 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
Command Processor interface.
Buffer management:
We use both the circular buffer and indirect buffers. To let the CP
execute something, you must allocate an indirect buffer by
Radeon_AllocIndirectBuffer(), fill it, and let it post via
Radeon_SendIndirectBuffer(). If you need some certain state before
your buffer is executed, you can define a state buffer: in this
buffer you write commands necessary to gain your whished state.
You get this state buffer during startup via Radeon_AllocIndirectBuffer()
and release it by Radeon_FreeIndirectBuffer() during shutdown.
Whenever you want to change (or free) it, call
Radeon_InvalidateStateBuffer() to make sure the state buffer is not
in use. Radeon_SendIndirectBuffer() keeps track of the current
state and if it's different then the state necessary for execution
of an indirect buffer, it submit the state buffer first. State
buffers are currently used for virtual cards only, but could be
used for things like 3D accelerator state as well.
All indirect buffers have the same size: 4K (Radeons want them to
be 4k aligned, so this is the minimum size). For 3D this may be too
small, but for 2D it's more then enough. To not waste main memory
(they cannot reside in graphics mem, at least my tests showed that
you get consistency problems), there are currently 253 buffers.
As the ring buffer only contains calls to indirect buffers and
each call needs at most 8 dwords, 2025 dwords would be sufficient.
Currently, there are 4K dwords circular buffer, which is more
then enough. Perhaps, engine synchronization code will be moved
from indirect to ring buffer to speed things up, in which case
the ring buffer might be too small.
Indirect buffers are recycled if there is none left. To track their
execution, each submitted buffer gets a tag (tags are numbered 0, 1...).
and put into a list. After execution, the tag is written to scratch
register 1 via CP. The recycler (Radeon_FreeIndirectBuffers())
compares the tags of submitted buffers with scratch register 1 to
detect finished buffers.
When you call any public function, you don't need to own any lock.
*/
#include "cp_regs.h"
//status_t Radeon_InitCP( accelerator_info *ai );
int Radeon_AllocIndirectBuffer( accelerator_info *ai, bool keep_lock );
void Radeon_FreeIndirectBuffer( accelerator_info *ai,
int buffer_idx, bool never_used );
void Radeon_SendIndirectBuffer( accelerator_info *ai,
int buffer_idx, int buffer_size,
int state_buffer_idx, int state_buffer_size, bool has_lock );
void Radeon_InvalidateStateBuffer( accelerator_info *ai, int state_buffer_idx );
void Radeon_FreeIndirectBuffers( accelerator_info *ai );
void Radeon_DiscardAllIndirectBuffers( accelerator_info *ai );
// get CPU address of indirect buffer
static inline uint32 *Radeon_GetIndirectBufferPtr( accelerator_info *ai, int buffer_idx )
{
return (uint32 *)(ai->mapped_memory[ai->si->cp.buffers.mem_type].data + ai->si->cp.buffers.mem_offset)
+ buffer_idx * INDIRECT_BUFFER_SIZE;
}
// start writing into indirect buffer
#define START_IB() \
{ \
int buffer_idx; \
uint32 *buffer_start, *buffer; \
\
buffer_idx = Radeon_AllocIndirectBuffer( ai, true ); \
buffer = buffer_start = Radeon_GetIndirectBufferPtr( ai, buffer_idx );
// write "write register" into indirect buffer
#define WRITE_IB_REG( reg, value ) \
do { buffer[0] = CP_PACKET0( (reg), 1 ); \
buffer[1] = (value); \
buffer += 2; } while( 0 )
// submit indirect buffer specific to virtual card
// stores tag of last command in engine.count
#define SUBMIT_IB_VC() \
Radeon_SendIndirectBuffer( ai, \
buffer_idx, buffer - buffer_start, \
vc->state_buffer_idx, vc->state_buffer_size, true ); \
}
// submit indirect buffer, not specific to virtual card
#define SUBMIT_IB() \
Radeon_SendIndirectBuffer( ai, \
buffer_idx, buffer - buffer_start, \
0, 0, true ); \
}
// write PACKET3 header, restricting block count
// command - command code
// count - whished number of blocks
// bytes_left - number of bytes left in buffer
// dwords_per_block - dwords per block
// dwords_in_header - dwords in header (i.e. dwords before the repeating blocks)
//
// the effective count is stored in "sub_count" substracted from "count";
// further, the first dwords of the packet is written
//
// remark: it's taken care of to keep in size of the buffer and the maximum number
// of bytes per command; the dword count as written into the first dword of the header
// is "size of body(!) in dwords - 1", which means "size of packet - 2"
#define WRITE_IB_PACKET3_HEAD( command, count, bytes_left, dwords_per_block, dwords_in_header ) \
sub_count = min( count, \
(min( bytes_left, (1 << 14) - 1 + 2) - dwords_in_header) / dwords_per_block ); \
count -= sub_count; \
*buffer++ = command | (((sub_count * dwords_per_block) + dwords_in_header - 2) << 16);
@@ -1,786 +0,0 @@
#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
+34 -38
View File
@@ -4,7 +4,7 @@
Part of Radeon accelerant
Hardware cursor support
Hardware cursor support.
*/
@@ -14,20 +14,20 @@
#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 );
static void doShowCursor( accelerator_info *ai, physical_head *head );
static void moveOneCursor( accelerator_info *ai, virtual_head *virtual_head, int x, int y );
// set standard foreground/background colours
void Radeon_SetCursorColors( accelerator_info *ai, virtual_port *port )
void Radeon_SetCursorColors( accelerator_info *ai, physical_head *head )
{
SHOW_FLOW0( 3, "" );
if( port->is_crtc2 ) {
Radeon_WriteRegCP( ai, RADEON_CUR2_CLR0, 0xffffff );
Radeon_WriteRegCP( ai, RADEON_CUR2_CLR1, 0 );
if( head->is_crtc2 ) {
OUTREG( ai->regs, RADEON_CUR2_CLR0, 0xffffff );
OUTREG( ai->regs, RADEON_CUR2_CLR1, 0 );
} else {
Radeon_WriteRegCP( ai, RADEON_CUR_CLR0, 0xffffff );
Radeon_WriteRegCP( ai, RADEON_CUR_CLR1, 0 );
OUTREG( ai->regs, RADEON_CUR_CLR0, 0xffffff );
OUTREG( ai->regs, RADEON_CUR_CLR1, 0 );
}
}
@@ -73,7 +73,6 @@ 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;
@@ -116,9 +115,9 @@ void MOVE_CURSOR(uint16 x, uint16 y)
y -= vds;
// go
moveOneCursor( ai, &vc->ports[0], x, y );
if( vc->independant_ports > 1 )
moveOneCursor( ai, &vc->ports[1], x, y );
moveOneCursor( ai, &vc->heads[0], x, y );
if( vc->independant_heads > 1 )
moveOneCursor( ai, &vc->heads[1], x, y );
RELEASE_BEN( ai->si->engine.lock );
}
@@ -131,54 +130,55 @@ void SHOW_CURSOR( bool is_visible )
SHOW_FLOW0( 4, "" );
// ACQUIRE_BEN( si->engine.lock );
ACQUIRE_BEN( ai->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] );
doShowCursor( ai, &ai->si->heads[vc->heads[0].physical_head] );
if( vc->independant_heads > 1 )
doShowCursor( ai, &ai->si->heads[vc->heads[1].physical_head] );
// RELEASE_BEN( si->engine.lock );
RELEASE_BEN( ai->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 )
void moveOneCursor( accelerator_info *ai, virtual_head *virtual_head, int x, int y )
{
virtual_card *vc = ai->vc;
physical_head *head = &ai->si->heads[virtual_head->physical_head];
int xorigin, yorigin;
bool prev_state;
// adjust according to relative screen position
x -= port->rel_x;
y -= port->rel_y;
x -= virtual_head->rel_x;
y -= virtual_head->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;
prev_state = head->cursor_on_screen;
head->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 ||
if( y > head->mode.timing.v_display ||
x > head->mode.timing.h_display ||
x <= -16 || y <= -16 )
{
port->cursor_on_screen = false;
head->cursor_on_screen = false;
}
if( prev_state != port->cursor_on_screen )
doShowCursor( ai, port );
if( prev_state != head->cursor_on_screen )
doShowCursor( ai, head );
if( !port->cursor_on_screen )
if( !head->cursor_on_screen )
return;
// if upper-left corner of cursor is outside of
@@ -192,9 +192,7 @@ void moveOneCursor( accelerator_info *ai, virtual_port *port, int x, int y )
if( y < 0 )
yorigin = -y;
Radeon_WaitForFifo( ai, 3 );
if( port->is_crtc2 ) {
if( head->is_crtc2 ) {
OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_OFF, RADEON_CUR2_LOCK
| (xorigin << 16)
| yorigin );
@@ -219,32 +217,30 @@ void moveOneCursor( accelerator_info *ai, virtual_port *port, int x, int y )
// 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 )
void doShowCursor( accelerator_info *ai, physical_head *head )
{
virtual_card *vc = ai->vc;
uint32 tmp;
if( port->is_crtc2 ) {
if( head->is_crtc2 ) {
tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL );
if( vc->cursor.is_visible && port->cursor_on_screen )
if( vc->cursor.is_visible && head->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 ) {
if( vc->cursor.is_visible && head->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 );
}
}
@@ -41,10 +41,10 @@
#include "radeon_accelerant.h"
#include "generic.h"
#include "cp_regs.h"
#include "rbbm_regs.h"
#include "GlobalData.h"
#include "mmio.h"
#include "CP.h"
static engine_token radeon_engine_token = { 1, B_2D_ACCELERATION, NULL };
@@ -56,32 +56,30 @@ uint32 ACCELERANT_ENGINE_COUNT(void)
return 1;
}
// write current token into CP stream
// write current sync token into CP stream;
// we instruct the CP to flush all kind of cache first to not interfere
// with subsequent host writes
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;
START_IB();
// flush pending data
buffer[idx++] = CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 );
buffer[idx++] = RADEON_RB2D_DC_FLUSH_ALL;
WRITE_IB_REG( RADEON_RB2D_DSTCACHE_CTLSTAT, 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_IB_REG( RADEON_WAIT_UNTIL, 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;
WRITE_IB_REG( RADEON_SCRATCH_REG0, ai->si->engine.count );
ai->si->engine.written = ai->si->engine.count;
Radeon_SendCP( ai, buffer, idx );
SUBMIT_IB();
}
// public function: acquire engine for future use
@@ -92,15 +90,14 @@ static void writeSyncToken( accelerator_info *ai )
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)
(void)capabilities;
(void)max_wait;
if( si->active_vc != vc->id )
Radeon_ActivateVirtualCard( ai );
ACQUIRE_BEN( si->engine.lock)
// wait for sync
if (st)
@@ -134,11 +131,12 @@ status_t RELEASE_ENGINE( engine_token *et, sync_token *st )
// public function: wait until engine is idle
// ??? which engine to wait for? Is there anyone using this function?
// is lock hold?
void WAIT_ENGINE_IDLE(void)
{
SHOW_FLOW0( 4, "" );
Radeon_Finish( ai );
Radeon_WaitForIdle( ai, false );
}
// public function: get sync token
@@ -161,7 +159,7 @@ status_t GET_SYNC_TOKEN( engine_token *et, sync_token *st )
}
// this is the same as the corresponding kernel function
static void spin( uint32 delay )
void Radeon_Spin( uint32 delay )
{
bigtime_t start_time;
@@ -177,21 +175,32 @@ 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 );
SHOW_FLOW( 4, "passed counter=%d",
((uint32 *)(ai->mapped_memory[si->cp.feedback.mem_type].data + si->cp.feedback.scratch_mem_offset))[0] );
//si->cp.scratch.ptr[0] );
// 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 )
if( (int32)(
((uint32 *)(ai->mapped_memory[si->cp.feedback.mem_type].data + si->cp.feedback.scratch_mem_offset))[0]
//si->cp.scratch.ptr[0]
- st->counter) >= 0 )
return B_OK;
/*if( (int32)(INREG( ai->regs, RADEON_SCRATCH_REG0 ) - st->counter) >= 0 )
return B_OK;*/
// commands have not been finished;
// this is a good time to free completed buffers as we have to
// busy-wait anyway
ACQUIRE_BEN( si->cp.lock );
Radeon_FreeIndirectBuffers( ai );
RELEASE_BEN( si->cp.lock );
sample_time = system_time();
@@ -204,14 +213,18 @@ status_t SYNC_TO_TOKEN( sync_token *st )
if( sample_time - start_time > 5000 )
snooze( (sample_time - start_time) / 10 );
else
spin( 1 );
Radeon_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*/ );
st->counter, /*INREG( ai->regs, RADEON_SCRATCH_REG0 )*/
((uint32 *)(ai->mapped_memory[si->cp.feedback.mem_type].data + si->cp.feedback.scratch_mem_offset))[0] );
//si->cp.scratch.ptr[0] );
Radeon_ResetEngine( ai );
return B_ERROR;
}
@@ -23,6 +23,8 @@ noted on a case by case below.
*/
void * get_accelerant_hook(uint32 feature, void *data) {
(void)data;
switch (feature) {
/*
These definitions are out of pure lazyness.
+4 -5
View File
@@ -11,7 +11,6 @@
#include "radeon_accelerant.h"
#include "GlobalData.h"
#include "generic.h"
#include <sys/ioctl.h>
#include <GraphicsDefs.h>
@@ -69,7 +68,7 @@ status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
*/
sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
{
// virtual_card *vc = ai->vc;
virtual_card *vc = ai->vc;
/*
NOTE:
@@ -81,10 +80,10 @@ sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
// 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;
int physical_head = vc->heads[0].physical_head;
//SHOW_INFO( 3, "semaphore: %x", ai->si->ports[physical_port].vblank );
//return ai->si->ports[physical_port].vblank;
return 0;
return ai->si->heads[physical_head].vblank;
//return B_ERROR;
}
@@ -10,6 +10,8 @@
#include "radeon_accelerant.h"
#endif
// the one and only we support
extern accelerator_info *ai;
+74 -17
View File
@@ -18,6 +18,7 @@
#include "fcntl.h"
#include <sys/ioctl.h>
#include <malloc.h>
#include "CP.h"
// init data used by both primary and cloned accelerant
@@ -51,22 +52,50 @@ static status_t init_common( int the_fd, bool accelerant_is_clone )
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);
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);
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;
}
if( ai->si->memory[mt_PCI].area > 0 ) {
ai->mapped_memory[mt_PCI].area = clone_area( "Radeon PCI GART area",
(void **)&ai->mapped_memory[mt_PCI].data, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, ai->si->memory[mt_PCI].area );
if( ai->mapped_memory[mt_PCI].area < 0 ) {
result = ai->mapped_memory[mt_PCI].area;
goto err4;
}
}
if( ai->si->memory[mt_AGP].area > 0 ) {
ai->mapped_memory[mt_AGP].area = clone_area( "Radeon AGP GART area",
(void **)&ai->mapped_memory[mt_AGP].data, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, ai->si->memory[mt_PCI].area );
if( ai->mapped_memory[mt_AGP].area < 0 ) {
result = ai->mapped_memory[mt_AGP].area;
goto err5;
}
}
ai->mapped_memory[mt_nonlocal] = ai->mapped_memory[ai->si->nonlocal_type];
ai->mapped_memory[mt_local].data = ai->si->local_mem;
return B_OK;
err5:
if( ai->mapped_memory[mt_PCI].area > 0 )
delete_area( ai->mapped_memory[mt_PCI].area );
err4:
delete_area( ai->regs_area );
err3:
delete_area( ai->shared_info_area );
err2:
@@ -79,6 +108,18 @@ err:
// clean up data common to both primary and cloned accelerant
static void uninit_common( void )
{
if( !ai->accelerant_is_clone ) {
Radeon_FreeVirtualCardStateBuffer( ai );
// the last accelerant should must wait for the card to become quite,
// else some nasty command could lunger in some FIFO
Radeon_WaitForIdle( ai, false );
}
if( ai->mapped_memory[mt_AGP].area > 0 )
delete_area( ai->mapped_memory[mt_AGP].area );
if( ai->mapped_memory[mt_PCI].area > 0 )
delete_area( ai->mapped_memory[mt_PCI].area );
delete_area( ai->regs_area );
delete_area( ai->shared_info_area );
delete_area( ai->virtual_card_area );
@@ -115,17 +156,18 @@ status_t INIT_ACCELERANT( int the_fd )
vc = ai->vc;
// init Command Processor
result = Radeon_InitCP( ai );
/*result = Radeon_InitCP( ai );
if( result != B_OK )
goto err2;
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 );
// establish connection to TV-Out unit
Radeon_DetectTVOut( ai );
// get all possible information about connected display devices
Radeon_DetectDisplays( ai );
// create list of supported modes
result = Radeon_CreateModeList( si );
@@ -133,7 +175,7 @@ status_t INIT_ACCELERANT( int the_fd )
goto err3;
/* init the shared semaphore */
INIT_BEN( "Radeon engine", si->engine.lock );
(void)INIT_BEN( si->engine.lock, "Radeon engine" );
// init engine sync token
// (count of issued parameters or commands)
@@ -147,17 +189,22 @@ status_t INIT_ACCELERANT( int the_fd )
si->overlay_mgr.inuse = 0;
// mark overlay as inactive
si->active_overlay.port = -1;
si->pending_overlay.port = -1;
si->active_overlay.head = -1;
si->pending_overlay.head = -1;
// reset list of allocated overlays
vc->overlay_buffers = NULL;
// mark engine as having no state
//si->cp.active_state_buffer = -1;
Radeon_AllocateVirtualCardStateBuffer( ai );
// everything else is initialized upon set_display_mode
return B_OK;
err3:
err2:
//err2:
uninit_common();
err:
return result;
@@ -167,6 +214,8 @@ err:
// public function: return size of clone info
ssize_t ACCELERANT_CLONE_INFO_SIZE( void )
{
SHOW_FLOW0( 0, "" );
// clone info is device name, so return its maximum size
return MAX_RADEON_DEVICE_NAME_LENGTH;
}
@@ -179,6 +228,8 @@ void GET_ACCELERANT_CLONE_INFO( void *data )
radeon_device_name dn;
status_t result;
SHOW_FLOW0( 0, "" );
// clone info is device name - ask device driver
dn.magic = RADEON_PRIVATE_DATA_MAGIC;
dn.name = (char *)data;
@@ -193,9 +244,11 @@ status_t CLONE_ACCELERANT( void *data )
status_t result;
char path[MAXPATHLEN];
int fd;
SHOW_FLOW0( 0, "" );
// create full device name
strcpy(path, "/dev/");//added trailing '/', this fixes cloning accelerant!
strcpy(path, "/dev/");
strcat(path, (const char *)data);
// open device; according to Be, permissions aren't important
@@ -233,6 +286,8 @@ void UNINIT_ACCELERANT( void )
// down BeOS; if both ports have been used, even the BIOS screen
// is completely messed up
SHOW_FLOW0( 0, "" );
// 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 );
@@ -244,6 +299,8 @@ void UNINIT_ACCELERANT( void )
// public function: get some info about graphics card
status_t GET_ACCELERANT_DEVICE_INFO( accelerant_device_info *di )
{
SHOW_FLOW0( 0, "" );
// is there anyone using it?
// TBD: everything apart from memsize
@@ -252,7 +309,7 @@ status_t GET_ACCELERANT_DEVICE_INFO( accelerant_device_info *di )
strcpy( di->chipset, "Radeon" );
strcpy( di->serial_no, "None" );
di->memory = ai->si->local_mem_size;
di->memory = ai->si->memory[mt_local].size;
// TBD: is max PLL speed really equal to max DAC speed?
di->dac_speed = ai->si->pll.max_pll_freq;
+10 -8
View File
@@ -2,6 +2,7 @@ SubDir OBOS_TOP src add-ons accelerants radeon ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics radeon ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
Addon radeon.accelerant : accelerants :
@@ -17,22 +18,23 @@ Addon radeon.accelerant : accelerants :
SetDisplayMode.c
crtc.c
dpms.c
engine_sync.c
driver_wrapper.c
flat_panel.c
monitor_detection.c
monitor_routing.c
multimon.c
overlay.c
overlay_management.c
palette.c
pll.c
settings.cpp
utils.c
log_coll.c
log_dump.c
ddc.c
dump_edid.c
edid.c
i2c.c
tv_out.c
: false
: libaccelerantscommon.a libgraphicscommon.a libradeon.a
;
LinkSharedOSLibs radeon.accelerant : root be ;
Package openbeos-radeon-cvs :
radeon.accelerant :
boot home config add-ons accelerants ;
@@ -10,7 +10,6 @@
#include "radeon_accelerant.h"
#include "generic.h"
#include <string.h>
#include <sys/ioctl.h>
#include "GlobalData.h"
#include "crtc_regs.h"
@@ -25,6 +24,9 @@
//#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
static const display_mode base_mode_list[] = {
// PAL
//{ { 25175, 640, 656, 752, 816, 480, 490, 492, 625, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ { 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 */
@@ -56,11 +58,6 @@ static const display_mode base_mode_list[] = {
{ { 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
@@ -108,8 +105,8 @@ bool Radeon_GetFormat( int space, int *format, int *bpp )
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,
status_t Radeon_ProposeDisplayMode( shared_info *si, physical_head *head,
general_pll_info *pll, display_mode *target,
const display_mode *low, const display_mode *high )
{
status_t result = B_OK;
@@ -119,7 +116,7 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_port *port,
int format, bpp;
uint32 row_bytes;
int eff_virtual_width;
// display_type_e disp_type;
fp_info *flatpanel = &si->flatpanels[head->flatpanel_port];
// save refresh rate - we want to leave this (artifical) value untouched
// don't use floating point, we are in kernel mode
@@ -136,20 +133,29 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_port *port,
// 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;
if( (head->chosen_displays & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) {
if( target->timing.h_display > flatpanel->panel_xres )
target->timing.h_display = flatpanel->panel_xres;
if( target->timing.v_display > flatpanel->panel_yres )
target->timing.v_display = flatpanel->panel_yres;
}
// the TV-Out encoder can "only" handle up to 1024x768
if( (head->chosen_displays & (dd_ctv | dd_stv)) != 0 ) {
if( target->timing.h_display > 1024 )
target->timing.h_display = 1024;
if( target->timing.v_display > 768 )
target->timing.v_display = 768;
}
// 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_fudge = Radeon_GetHSyncFudge( head, 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;
@@ -328,8 +334,8 @@ status_t Radeon_ProposeDisplayMode( shared_info *si, physical_port *port,
// 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;
if ((row_bytes * target->virtual_height) > si->memory[mt_local].size - 1024 )
target->virtual_height = (si->memory[mt_local].size - 1024) / row_bytes;
// make sure we haven't shrunk virtual height too much
if (target->virtual_height < target->timing.v_display) {
@@ -425,7 +431,7 @@ static void checkAndAddMode( accelerator_info *ai, const display_mode *mode, boo
*dst = *mode;
dst->space = low.space = high.space = spaces[i];
if( Radeon_ProposeDisplayMode( si, &si->ports[0],
if( Radeon_ProposeDisplayMode( si, &si->heads[0],
&si->pll, dst, &low, &high ) == B_OK )
{
si->mode_count++;
@@ -436,7 +442,7 @@ static void checkAndAddMode( accelerator_info *ai, const display_mode *mode, boo
*dst = *mode;
dst->space = spaces[i];
if( Radeon_ProposeDisplayMode( si, &si->ports[1],
if( Radeon_ProposeDisplayMode( si, &si->heads[1],
&si->pll, dst, &low, &high ) == B_OK )
{
si->mode_count++;
@@ -474,9 +480,11 @@ static void checkAndAddMultiMode( accelerator_info *ai, const display_mode *mode
}
// add display mode of flat panel to official list
static void addFPMode( accelerator_info *ai, fp_info *fp_info )
static void addFPMode( shared_info *si )
{
if( fp_info->disp_type == dt_dvi_1 || fp_info->disp_type == dt_lvds ) {
fp_info *fp_info = &si->flatpanels[0];
if( (si->connected_displays & (dd_dvi | dd_lvds)) != 0 ) {
display_mode mode;
mode.virtual_width = mode.timing.h_display = fp_info->panel_xres;
@@ -547,7 +555,7 @@ status_t Radeon_CreateModeList( shared_info *si )
checkAndAddMultiMode( ai, &base_mode_list[i], false );
// plus fp mode
addFPMode( ai, &si->fp_port );
addFPMode( si );
// as we've created the list ourself, we don't clone it
ai->mode_list_area = si->mode_list_area;
@@ -572,28 +580,40 @@ status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
status_t result1, result2;
bool isTunneled;
status_t result;
display_mode tmp_target;
// check whether we got a tunneled settings command
result = Radeon_CheckMultiMonTunnel( vc, target, low, high, &isTunneled );
if( isTunneled )
return result;
// check how many heads are needed by target mode
tmp_target = *target;
Radeon_DetectMultiMode( vc, &tmp_target );
// before checking multi-monitor mode, we must define a monitor signal routing
// TBD: this may be called a bit too frequently if someone scans available modes
// via successive Propose_Display_Mode; though this doesn't do any _real_ harm
// it leads to annoying distortions on screen!!
Radeon_DetectDisplays( ai);
Radeon_SetupDefaultMonitorRouting( ai, Radeon_DifferentPorts( &tmp_target ) );
// 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)",
SHOW_FLOW0( 3, "wished:" );
SHOW_FLOW( 3, "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)",
SHOW_FLOW( 3, "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 );
SHOW_FLOW( 3, "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],
result1 = Radeon_ProposeDisplayMode( si, &si->heads[vc->heads[0].physical_head],
&si->pll, target, low, high );
if( result1 == B_ERROR )
@@ -601,7 +621,7 @@ status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
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],
result2 = Radeon_ProposeDisplayMode( si, &si->heads[vc->heads[1].physical_head],
&si->pll, target, low, high );
if( result2 == B_ERROR )
@@ -610,14 +630,14 @@ status_t PROPOSE_DISPLAY_MODE( display_mode *target, const display_mode *low,
result2 = B_OK;
}
SHOW_INFO0( 2, "got:" );
SHOW_INFO( 2, "H: %4d %4d %4d %4d (v=%4d)",
SHOW_INFO0( 4, "got:" );
SHOW_INFO( 4, "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)",
SHOW_INFO( 4, "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 );
SHOW_INFO( 4, "clk: %ld", target->timing.pixel_clock );
Radeon_HideMultiMode( vc, target );
+131 -197
View File
@@ -23,34 +23,6 @@
#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 )
@@ -90,8 +62,8 @@ static struct {
{ RADEON_SUBPIC_CNTL, 0 },
{ RADEON_VIPH_CONTROL, 0 },
{ RADEON_I2C_CNTL_1, 0 },
{ RADEON_GEN_INT_CNTL, 0 },
{ RADEON_CAP0_TRIG_CNTL, 0 },
//{ RADEON_GEN_INT_CNTL, 0 }, // VBI irqs are handled seperately
//{ RADEON_CAP0_TRIG_CNTL, 0 }, // leave capturing on during mode switch
};
static void Radeon_InitCommonRegs( accelerator_info *ai )
@@ -103,35 +75,39 @@ static void Radeon_InitCommonRegs( accelerator_info *ai )
OUTREG( regs, common_regs[i].reg, common_regs[i].val );
}
// set display mode of one port;
// set display mode of one head;
// 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 )
void Radeon_SetMode( accelerator_info *ai, physical_head *head, 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;
display_device_e disp_devices;
fp_info *fp_info;
port_regs values;
tv_params tv_params;
tv_standard tv_format = ts_ntsc;
tv_timing *tv_timing = &Radeon_std_tv_timing[tv_format];
bool internal_tv_encoder;
port->mode = *mode;
head->mode = *mode;
// don't destroy passed values, use our copy instead
mode = &port->mode;
mode = &head->mode;
disp_type = si->ports[port->physical_port].disp_type;
disp_devices = head->chosen_displays;
fp_info = &si->flatpanels[head->flatpanel_port];
// 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( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext )) != 0 ) {
if( mode->timing.h_display > fp_info->panel_xres )
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.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;
@@ -142,48 +118,110 @@ void Radeon_SetMode( accelerator_info *ai, virtual_port *port, display_mode *mod
mode->timing.pixel_clock = fp_info->dot_clock;
}
// if using TV-Out, the timing of the source signal must be tweaked to
// get proper timing
internal_tv_encoder = si->tv_chip != tc_external_rt1;
// we need higher accuracy then Be thought of;
mode->timing.pixel_clock *= 1000;
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
display_mode tweaked_mode;
Radeon_CalcTVParams( &si->pll, &tv_params, tv_timing, internal_tv_encoder,
mode, &tweaked_mode );
*mode = tweaked_mode;
}
Radeon_GetFormat( mode->space, &format, &bpp );
vc->bpp = bpp;
vc->datatype = format;
vc->datatype = format;
// time to read original register content
// lock hardware so noone bothers us
Radeon_WaitForIdle( ai, true );
Radeon_ReadCRTCRegisters( ai, head, &values );
Radeon_ReadMonitorRoutingRegs( ai, head, &values );
if( (disp_devices & (dd_dvi | dd_lvds | dd_dvi_ext)) != 0 ) {
if( !head->is_crtc2 )
Radeon_ReadRMXRegisters( ai, &values );
Radeon_ReadFPRegisters( ai, &values );
}
// calculate all hardware register values
Radeon_CalcCRTCRegisters( ai, port, mode, &values );
Radeon_CalcCRTCRegisters( ai, head, 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( mode->timing.pixel_clock ) {
Radeon_CalcPLLRegisters( &si->pll, mode/*->timing.pixel_clock / 10*/,
(/*(disp_devices & (dd_stv | dd_ctv)) != 0 ? &tv_params.crt_dividers : */NULL),
&values );
}
if( disp_type == dt_dvi_1 || disp_type == dt_lvds )
Radeon_CalcFPRegisters( ai, port, &si->fp_port, mode, &values );
// for first CRTC1, we need to setup RMX properly
if( !head->is_crtc2 )
Radeon_CalcRMXRegisters( fp_info, mode,
(disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0,
&values );
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
Radeon_CalcFPRegisters( ai, head, fp_info, &values );
if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) {
Radeon_CalcTVRegisters( ai, mode, tv_timing, &tv_params, &values,
head, internal_tv_encoder, tv_format );
}
Radeon_CalcMonitorRouting( ai, head, &values );
// we don't use pixel clock anymore, so it can be reset to Be's kHz
mode->timing.pixel_clock /= 1000;
// write values to registers
Radeon_SetDPMS( ai, port, B_DPMS_SUSPEND );
// we first switch off all output, so the monitor(s) won't get invalid signals
Radeon_SetDPMS( ai, head, B_DPMS_SUSPEND );
Radeon_InitCommonRegs( ai );
Radeon_ProgramCRTCRegisters( ai, port, &values );
Radeon_ProgramCRTCRegisters( ai, head, &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( !head->is_crtc2 )
Radeon_ProgramRMXRegisters( ai, &values );
if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 )
Radeon_ProgramFPRegisters( ai, head, fp_info, &values );
if( mode->timing.pixel_clock )
Radeon_ProgramPLL( ai, port, &values );
//if( mode->timing.pixel_clock )
Radeon_ProgramPLL( ai, head, &values );
if( (disp_devices & (dd_ctv | dd_stv)) != 0 )
Radeon_ProgramTVRegisters( ai, &values, internal_tv_encoder );
Radeon_ProgramMonitorRouting( ai, head, &values );
Radeon_SetDPMS( ai, port, B_DPMS_ON );
head->active_displays = disp_devices;
// programming is over, so hardware can be used again
RELEASE_BEN( si->cp.lock );
// well done - switch display(s) on
Radeon_SetDPMS( ai, head, 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;
si->active_overlay.head = -1;
}
@@ -196,7 +234,7 @@ void Radeon_EnableIRQ( accelerator_info *ai, bool enable )
int_cntl = INREG( ai->regs, RADEON_GEN_INT_CNTL );
int_mask =
RADEON_CRTC_VBLANK_MASK
| (si->has_crtc2 ? RADEON_CRTC2_VBLANK_MASK : 0);
| (si->num_heads > 1 ? RADEON_CRTC2_VBLANK_MASK : 0);
if( enable )
int_cntl |= int_mask;
@@ -238,7 +276,7 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
}
// already done by propose_display_mode, but it was undone on return;
// do this before equality check to recognize changed to multi-monitor mode
// do this before equality check to recognize changes of multi-monitor mode
Radeon_DetectMultiMode( vc, &mode );
// mode switches can take quite long and are visible,
@@ -247,25 +285,27 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
RELEASE_BEN( si->engine.lock );
return B_OK;
}
// make sure, we don't get disturbed
Radeon_Finish( ai );
//Radeon_Finish( ai );
Radeon_EnableIRQ( ai, false );
// free cursor and framebuffer memory
{
radeon_free_local_mem fm;
radeon_free_mem fm;
fm.magic = RADEON_PRIVATE_DATA_MAGIC;
fm.memory_type = mt_local;
fm.global = true;
if( vc->cursor.mem_handle ) {
fm.handle = vc->cursor.mem_handle;
ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm );
ioctl( ai->fd, RADEON_FREE_MEM, &fm );
}
if( vc->fb_mem_handle ) {
fm.handle = vc->fb_mem_handle;
ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm );
ioctl( ai->fd, RADEON_FREE_MEM, &fm );
}
}
@@ -278,24 +318,26 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
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->independant_heads = Radeon_NeedsSecondPort( &mode ) ? 2 : 1;
vc->different_heads = Radeon_DifferentPorts( &mode );
SHOW_FLOW( 2, "independant heads: %d", vc->independant_heads );
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;
radeon_alloc_mem am;
int format, bpp;
// alloc cursor memory
am.magic = RADEON_PRIVATE_DATA_MAGIC;
am.size = 1024;
am.memory_type = mt_local;
am.global = true;
if( ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am ) == B_OK ) {
if( ioctl( ai->fd, RADEON_ALLOC_MEM, &am ) == B_OK ) {
vc->cursor.mem_handle = am.handle;
vc->cursor.fb_offset = am.fb_offset;
vc->cursor.fb_offset = am.offset;
} else {
// too bad that we are out of mem -> set reasonable values as
// it's too late to give up (ouch!)
@@ -304,16 +346,16 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
vc->cursor.fb_offset = 0;
}
vc->cursor.data = si->framebuffer + vc->cursor.fb_offset;
vc->cursor.data = si->local_mem + 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 ) {
if( ioctl( ai->fd, RADEON_ALLOC_MEM, &am ) == B_OK ) {
vc->fb_mem_handle = am.handle;
vc->fb_offset = am.fb_offset;
vc->fb_offset = am.offset;
} else {
// ouch again - set reasonable values
SHOW_ERROR0( 2, "no memory for frame buffer!" );
@@ -321,52 +363,55 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
vc->fb_offset = 1024;
}
vc->fbc.frame_buffer = si->framebuffer + vc->fb_offset;
vc->fbc.frame_buffer = si->local_mem + vc->fb_offset;
vc->fbc.frame_buffer_dma = (void *)((uint8 *)si->framebuffer_pci + vc->fb_offset);
vc->fbc.bytes_per_row = vc->pitch;
SHOW_FLOW( 0, "frame buffer CPU-address=%x, phys-address=%x",
vc->fbc.frame_buffer, vc->fbc.frame_buffer_dma );
}
// multi-screen stuff
Radeon_InitMultiModeVars( vc, &mode );
// GO!
Radeon_SetMode( ai, &vc->ports[0], &mode );
Radeon_SetMode( ai, &si->heads[vc->heads[0].physical_head], &mode );
if( vc->independant_ports > 1 )
Radeon_SetMode( ai, &vc->ports[1], &mode );
if( vc->independant_heads > 1 )
Radeon_SetMode( ai, &si->heads[vc->heads[1].physical_head], &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 );
// setup 2D registers
Radeon_Init2D( ai );
// setup position of framebuffer for 2D commands
Radeon_FillStateBuffer( 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] );
Radeon_InitPalette( ai, &si->heads[vc->heads[0].physical_head] );
if( vc->independant_heads > 1 )
Radeon_InitPalette( ai, &si->heads[vc->heads[1].physical_head] );
// initialize cursor data
Radeon_SetCursorColors( ai, &vc->ports[0] );
if( vc->independant_ports > 1 )
Radeon_SetCursorColors( ai, &vc->ports[1] );
Radeon_SetCursorColors( ai, &si->heads[vc->heads[0].physical_head] );
if( vc->independant_heads > 1 )
Radeon_SetCursorColors( ai, &si->heads[vc->heads[1].physical_head] );
// 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 );
Radeon_EnableIRQ( ai, true );
RELEASE_BEN( si->engine.lock );
@@ -380,114 +425,3 @@ status_t SET_DISPLAY_MODE( display_mode *mode_in )
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] );
}
+92 -52
View File
@@ -8,34 +8,40 @@
*/
#include "radeon_accelerant.h"
//#include "../include/radeon_regs.h"
#include "mmio.h"
#include "crtc_regs.h"
#include "dac_regs.h"
#include "GlobalData.h"
// read old CRTC register content
void Radeon_ReadCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values )
{
vuint8 *regs = ai->regs;
// only CRTC_EXT_CNTL is programmed by someone else (namely the monitor
// router); if more registers are affected, you must read them here too!
if( !head->is_crtc2 ) {
values->crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL );
}
}
// hammer CRTC registers
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, virtual_port *port,
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values )
{
vuint8 *regs = ai->regs;
SHOW_FLOW0( 2, "" );
if( port->is_crtc2 ) {
if( head->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 );
@@ -49,10 +55,11 @@ void Radeon_ProgramCRTCRegisters( accelerator_info *ai, virtual_port *port,
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl,
RADEON_CRTC_VSYNC_DIS |
RADEON_CRTC_HSYNC_DIS |
RADEON_CRTC_DISPLAY_DIS );
RADEON_CRTC_DISPLAY_DIS |
RADEON_CRTC_CRT_ON );
OUTREGP( regs, RADEON_DAC_CNTL, values->dac_cntl,
RADEON_DAC_RANGE_CNTL | RADEON_DAC_BLANKING );
RADEON_DAC_RANGE_CNTL_MASK | 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 );
@@ -65,14 +72,13 @@ void Radeon_ProgramCRTCRegisters( accelerator_info *ai, virtual_port *port,
// get required hsync delay depending on bit depth and output device
uint16 Radeon_GetHSyncFudge( shared_info *si, physical_port *port, int datatype )
uint16 Radeon_GetHSyncFudge( physical_head *head, 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 )
if( (head->chosen_displays & (dd_dvi | dd_dvi_ext | dd_lvds )) != 0 )
return hsync_fudge_fp[datatype - 1];
else
return hsync_fudge_default[datatype - 1];
@@ -80,48 +86,24 @@ uint16 Radeon_GetHSyncFudge( shared_info *si, physical_port *port, int datatype
// calculate CRTC register content
void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
void Radeon_CalcCRTCRegisters( accelerator_info *ai, physical_head *head,
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 );
hsync_fudge = Radeon_GetHSyncFudge( head, vc->datatype );
if( port->is_crtc2 ) {
if( head->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?)
@@ -129,13 +111,9 @@ void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
| 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;
RADEON_XCRT_CNT_EN;
values->dac_cntl = RADEON_DAC_MASK_ALL
| RADEON_DAC_VGA_ADR_EN
@@ -150,7 +128,6 @@ void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
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)
@@ -162,8 +139,7 @@ void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
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 =
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
@@ -177,3 +153,67 @@ void Radeon_CalcCRTCRegisters( accelerator_info *ai, virtual_port *port,
values->crtc_pitch |= values->crtc_pitch << 16;
}
// update shown are of one port
static void moveOneDisplay( accelerator_info *ai, virtual_head *virtual_head )
{
virtual_card *vc = ai->vc;
uint32 offset;
offset = (vc->mode.v_display_start + virtual_head->rel_y) * vc->pitch +
(vc->mode.h_display_start + virtual_head->rel_x) * vc->bpp +
vc->fb_offset;
SHOW_FLOW( 3, "Setting address %x on port %d",
offset, virtual_head->physical_head );
OUTREG( ai->regs, virtual_head->physical_head ? RADEON_CRTC2_OFFSET : RADEON_CRTC_OFFSET, offset );
}
// internal function: pan display
// engine lock should be hold
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->heads[0] );
if( vc->independant_heads > 1 )
moveOneDisplay( ai, &vc->heads[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;
}
-21
View File
@@ -1,21 +0,0 @@
/*
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
+137 -84
View File
@@ -11,31 +11,22 @@
#include "mmio.h"
#include "crtc_regs.h"
#include "fp_regs.h"
#include "pll_regs.h"
#include "pll_access.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;
shared_info *si = ai->si;
status_t result1, result2;
result1 = Radeon_SetDPMS( ai, &vc->ports[0], dpms_flags );
result1 = Radeon_SetDPMS( ai, &si->heads[vc->heads[0].physical_head], dpms_flags );
if( vc->independant_ports > 1 )
result2 = Radeon_SetDPMS( ai, &vc->ports[1], dpms_flags );
if( vc->independant_heads > 1 )
result2 = Radeon_SetDPMS( ai, &si->heads[vc->heads[1].physical_head], dpms_flags );
else
result2 = B_OK;
@@ -55,47 +46,101 @@ uint32 DPMS_CAPABILITIES(void)
// 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] );
// we just ask the primary head what status it is in
return Radeon_GetDPMS( ai, &ai->si->heads[ai->vc->heads[0].physical_head] );
}
// set DPMS mode of one port
status_t Radeon_SetDPMS( accelerator_info *ai, virtual_port *port, int mode )
// set DPMS state of LVDS port
static void Radeon_SetDPMS_LVDS( accelerator_info *ai, 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;
vuint8 *regs = ai->regs;
// for internal flat panel, switch backlight off too
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: {
uint32 old_pixclks_cntl;
old_pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL);
// ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero
if( ai->si->is_mobility || ai->si->asic == rt_rs100 )
Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb );
OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_DISPLAY_DIS,
~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) );
if( ai->si->is_mobility || ai->si->asic == rt_rs100 )
Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, old_pixclks_cntl );
break; }
}
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 )
// set DPMS state of DVI port
static void Radeon_SetDPMS_DVI( accelerator_info *ai, int mode )
{
if( port->is_crtc2 )
return Radeon_GetDPMS_CRTC2( ai );
else
return Radeon_GetDPMS_CRTC1( ai );
vuint8 *regs = ai->regs;
// 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)
switch( mode ) {
case B_DPMS_ON:
OUTREGP( regs, RADEON_FP_GEN_CNTL, RADEON_FP_FPON | RADEON_FP_TMDS_EN,
~(RADEON_FP_FPON | RADEON_FP_TMDS_EN));
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREGP( regs, RADEON_FP_GEN_CNTL, 0, ~RADEON_FP_FPON | RADEON_FP_TMDS_EN );
break;
}
}
// set DPMS state of external DVI port
static void Radeon_SetDPMS_FP2( accelerator_info *ai, int mode )
{
vuint8 *regs = ai->regs;
// 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)
switch( mode ) {
case B_DPMS_ON:
OUTREGP( regs, RADEON_FP2_GEN_CNTL,
RADEON_FP_FPON |
(ai->si->asic >= rt_r200 ? RADEON_FP2_DV0_EN : 0),
~(RADEON_FP2_BLANK_EN | RADEON_FP2_BLANK_EN) );
break;
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
OUTREGP( regs, RADEON_FP2_GEN_CNTL, 0, ~(RADEON_FP2_BLANK_EN | RADEON_FP2_BLANK_EN) );
break;
}
}
// set DPMS mode for first port
status_t Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode )
static void 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
@@ -120,54 +165,12 @@ status_t Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode )
/* 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 )
static void Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode )
{
vuint8 *regs = di->regs;
@@ -194,10 +197,50 @@ status_t Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode )
/* Screen: Off; HSync: Off, VSync: Off */
OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, mask, ~mask );
break;
}
}
// set DPMS mode of one port
// engine lock is assumed to be hold
status_t Radeon_SetDPMS( accelerator_info *ai, physical_head *head, 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;
}*/
// test validity of mode once and for all
switch( mode ) {
case B_DPMS_ON:
case B_DPMS_STAND_BY:
case B_DPMS_SUSPEND:
case B_DPMS_OFF:
break;
default:
return B_BAD_VALUE;
}
if( head->is_crtc2 )
Radeon_SetDPMS_CRTC2( ai, mode );
else
Radeon_SetDPMS_CRTC1( ai, mode );
if( (head->active_displays & dd_lvds) != 0 )
Radeon_SetDPMS_LVDS( ai, mode );
if( (head->active_displays & dd_dvi) != 0 )
Radeon_SetDPMS_DVI( ai, mode );
if( (head->active_displays & dd_dvi_ext) != 0 )
Radeon_SetDPMS_FP2( ai, mode );
return B_OK;
}
@@ -240,3 +283,13 @@ uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di )
return B_DPMS_OFF;
}
// get DPMS mode of one port
uint32 Radeon_GetDPMS( accelerator_info *ai, physical_head *head )
{
if( head->is_crtc2 )
return Radeon_GetDPMS_CRTC2( ai );
else
return Radeon_GetDPMS_CRTC1( ai );
}
@@ -0,0 +1,78 @@
/*
Copyright (c) 2003, Thomas Kurschel
Part of Radeon accelerant
Kernel driver wrapper
*/
#include "radeon_accelerant.h"
#include <sys/ioctl.h>
status_t Radeon_WaitForIdle( accelerator_info *ai, bool keep_lock )
{
radeon_wait_for_idle wfi;
wfi.magic = RADEON_PRIVATE_DATA_MAGIC;
wfi.keep_lock = keep_lock;
return ioctl( ai->fd, RADEON_WAITFORIDLE, &wfi, sizeof( wfi ));
}
void Radeon_ResetEngine( accelerator_info *ai )
{
radeon_no_arg na;
na.magic = RADEON_PRIVATE_DATA_MAGIC;
ioctl( ai->fd, RADEON_RESETENGINE, &na, sizeof( na ));
}
status_t Radeon_VIPRead( accelerator_info *ai, uint channel, uint address, uint32 *data )
{
radeon_vip_read vr;
status_t res;
vr.magic = RADEON_PRIVATE_DATA_MAGIC;
vr.channel = channel;
vr.address = address;
res = ioctl( ai->fd, RADEON_VIPREAD, &vr, sizeof( vr ));
if( res == B_OK )
*data = vr.data;
return res;
}
status_t Radeon_VIPWrite( accelerator_info *ai, uint8 channel, uint address, uint32 data )
{
radeon_vip_write vw;
vw.magic = RADEON_PRIVATE_DATA_MAGIC;
vw.channel = channel;
vw.address = address;
vw.data = data;
return ioctl( ai->fd, RADEON_VIPWRITE, &vw, sizeof( vw ));
}
int Radeon_FindVIPDevice( accelerator_info *ai, uint32 device_id )
{
radeon_find_vip_device fvd;
status_t res;
fvd.magic = RADEON_PRIVATE_DATA_MAGIC;
fvd.device_id = device_id;
res = ioctl( ai->fd, RADEON_FINDVIPDEVICE, &fvd, sizeof( fvd ));
if( res == B_OK )
return fvd.channel;
else
return -1;
}
-146
View File
@@ -1,146 +0,0 @@
/*
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
@@ -1,278 +0,0 @@
/*
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
@@ -1,247 +0,0 @@
/*
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;
}
+144 -191
View File
@@ -8,46 +8,54 @@
*/
#include "radeon_accelerant.h"
#include <malloc.h>
#include "mmio.h"
#include "fp_regs.h"
#include "ddc_regs.h"
#include "utils.h"
#include "ddc.h"
#include "crtc_regs.h"
#include "pll_regs.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 )
void Radeon_ReadRMXRegisters( accelerator_info *ai, port_regs *values )
{
vuint8 *regs = ai->regs;
values->fp_horz_stretch = INREG( regs, RADEON_FP_HORZ_STRETCH );
values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH );
}
void Radeon_CalcRMXRegisters( fp_info *flatpanel, display_mode *mode, bool use_rmx, port_regs *values )
{
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( !use_rmx ) {
// disable RMX unit if requested
values->fp_horz_stretch &=
~(RADEON_HORZ_STRETCH_BLEND |
RADEON_HORZ_STRETCH_ENABLE);
if( xres > fp_port->panel_xres )
xres = fp_port->panel_xres;
if( yres > fp_port->panel_yres )
yres = fp_port->panel_yres;
values->fp_vert_stretch &=
~(RADEON_VERT_STRETCH_ENABLE |
RADEON_VERT_STRETCH_BLEND);
return;
}
// RMX unit can only upscale, not downscale
if( xres > flatpanel->panel_xres )
xres = flatpanel->panel_xres;
if( yres > flatpanel->panel_yres )
yres = flatpanel->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;
Hratio = FIX_SCALE * (uint32)xres / flatpanel->panel_xres;
Vratio = FIX_SCALE * (uint32)yres / flatpanel->panel_yres;
// save it for overlay unit (overlays must be vertically scaled manually)
flatpanel->h_ratio = Hratio;
flatpanel->v_ratio = Vratio;
fp_port->h_ratio = Hratio;
fp_port->v_ratio = Vratio;
values->fp_horz_stretch = flatpanel->panel_xres << RADEON_HORZ_PANEL_SIZE_SHIFT;
if( Hratio == FIX_SCALE ) {
values->fp_horz_stretch &=
@@ -69,6 +77,8 @@ void Radeon_CalcFPRegisters( accelerator_info *ai, virtual_port *port, fp_info *
}
values->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO;
values->fp_vert_stretch = flatpanel->panel_yres << RADEON_VERT_PANEL_SIZE_SHIFT;
if( Vratio == FIX_SCALE ) {
values->fp_vert_stretch &=
~(RADEON_VERT_STRETCH_ENABLE |
@@ -87,187 +97,130 @@ void Radeon_CalcFPRegisters( accelerator_info *ai, virtual_port *port, fp_info *
RADEON_VERT_STRETCH_BLEND;
}
values->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN;
}
// write RMX registers
void Radeon_ProgramRMXRegisters( accelerator_info *ai, port_regs *values )
{
vuint8 *regs = ai->regs;
OUTREG( regs, RADEON_FP_HORZ_STRETCH, values->fp_horz_stretch );
OUTREG( regs, RADEON_FP_VERT_STRETCH, values->fp_vert_stretch );
}
void Radeon_ReadFPRegisters( accelerator_info *ai, port_regs *values )
{
vuint8 *regs = ai->regs;
values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL );
values->fp2_gen_cntl = INREG( regs, RADEON_FP2_GEN_CNTL );
values->lvds_gen_cntl = INREG( regs, RADEON_LVDS_GEN_CNTL );
values->fp_h_sync_strt_wid = INREG( regs, RADEON_FP_H_SYNC_STRT_WID );
values->fp_v_sync_strt_wid = INREG( regs, RADEON_FP_V_SYNC_STRT_WID );
values->fp2_h_sync_strt_wid = INREG( regs, RADEON_FP_H2_SYNC_STRT_WID );
values->fp2_v_sync_strt_wid = INREG( regs, RADEON_FP_V2_SYNC_STRT_WID );
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 );
}
// calculcate flat panel crtc registers;
// must be called after normal CRTC registers are determined
void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values )
{
// setup synchronization position
// (most values are ignored according to fp_gen_cntl, but at least polarity
// and pixel precise horizontal sync position are always used)
if( fp_port->is_fp2 ) {
values->fp2_h_sync_strt_wid = values->crtc_h_sync_strt_wid;
values->fp2_v_sync_strt_wid = values->crtc_v_sync_strt_wid;
} else {
values->fp_h_sync_strt_wid = values->crtc_h_sync_strt_wid;
values->fp_v_sync_strt_wid = values->crtc_v_sync_strt_wid;
}
if( fp_port->is_fp2 )
values->fp2_gen_cntl = 0;
else {
// setup magic CRTC shadowing
values->fp_gen_cntl &=
~(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 = 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;
// enable proper transmitter
if( (head->chosen_displays & dd_lvds) != 0 ) {
// using LVDS means there cannot be a DVI monitor
values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
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);
} else if( !fp_port->is_fp2 ) {
// DVI on internal transmitter
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;*/
} else {
// DVI on external transmitter
values->fp2_gen_cntl |= RADEON_FP2_FPON | RADEON_FP_PANEL_FORMAT;
values->fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN;
if( ai->si->asic >= rt_r200 )
values->fp2_gen_cntl |= RADEON_FP2_DV0_EN;
}
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 )
void Radeon_ProgramFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values )
{
uint32 tmp;
shared_info *si = ai->si;
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 );
}
}
OUTREG( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl );
if( fp_port->is_fp2 ) {
OUTREG( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl );
OUTREG( regs, RADEON_FP_H2_SYNC_STRT_WID, values->fp2_h_sync_strt_wid );
OUTREG( regs, RADEON_FP_V2_SYNC_STRT_WID, values->fp2_v_sync_strt_wid );
} else {
OUTREG( regs, RADEON_FP_H_SYNC_STRT_WID, values->fp_h_sync_strt_wid );
OUTREG( regs, RADEON_FP_V_SYNC_STRT_WID, values->fp_v_sync_strt_wid );
}
}
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;
}
}
// workaround for old AIW Radeon having display buffer underflow
// in conjunction with DVI
if( si->num_heads == 1 ) {
OUTREG( regs, RADEON_GRPH_BUFFER_CNTL,
INREG( regs, RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000);
}
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;
if( (head->chosen_displays & dd_lvds) != 0 ) {
OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl,
RADEON_LVDS_ON | RADEON_LVDS_BLON );
}
// disable auto-centering
// (we setup everything ourself, and if we switch from flat panel to CRT
// on CRTC1, we don't need this stuff anyway)
OUTREG( regs, RADEON_CRTC_MORE_CNTL, 0 );
}
-69
View File
@@ -1,69 +0,0 @@
/*
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
@@ -1,129 +0,0 @@
/*
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
@@ -1,76 +0,0 @@
/*
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
@@ -1,75 +0,0 @@
/*
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
@@ -1,17 +0,0 @@
/*
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
@@ -1,18 +0,0 @@
/*
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,
};
@@ -1,18 +0,0 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon driver
Fast logger - event names
*/
char *log_names[] = {
"_Radeon_FlushPixelCache",
"_Radeon_WaitForFifo",
"_Radeon_WaitForIdle",
"_Radeon_WriteRegFifo",
"_GetAvailRingBufferQueue",
"_Radeon_Finish",
"_Radeon_SendCP",
};
@@ -0,0 +1,687 @@
/*
Copyright (c) 2002,03 Thomas Kurschel
Part of Radeon accelerant
Monitor detection
*/
#include "radeon_accelerant.h"
#include "mmio.h"
#include "crtc_regs.h"
#include "dac_regs.h"
#include "pll_regs.h"
#include "tv_out_regs.h"
#include "config_regs.h"
#include "ddc_regs.h"
#include "gpiopad_regs.h"
#include "pll_access.h"
#include "ddc.h"
#include <malloc.h>
typedef struct {
accelerator_info *ai;
uint32 port;
} ddc_port_info;
// get I2C signals
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;
}
// set I2C signals
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;
}
/*
// check whether there is a monitor by talking to him via DDC2
// ddc_port - register to use for DDC2 communication
static bool Radeon_DetectMonitorViaDDC( accelerator_info *ai, uint32 ddc_port )
{
i2c_bus bus;
ddc_port_info info;
edid1_info edid;
void *vdif;
size_t vdif_len;
status_t res;
info.ai = ai;
info.port = ddc_port;
bus.cookie = &info;
bus.set_signals = &set_signals;
bus.get_signals = &get_signals;
res = ddc2_read_edid1( &bus, &edid, &vdif, &vdif_len );
if( res != B_OK )
return false;
if( vdif != NULL )
free( vdif );
SHOW_INFO( 2, "Found monitor on DDC port 0x%04x", ddc_port );
return true;
}
*/
// read EDID information from monitor
// ddc_port - register to use for DDC2 communication
bool Radeon_ReadEDID( accelerator_info *ai, uint32 ddc_port, edid1_info *edid )
{
i2c_bus bus;
ddc_port_info info;
void *vdif;
size_t vdif_len;
status_t res;
info.ai = ai;
info.port = ddc_port;
bus.cookie = &info;
bus.set_signals = &set_signals;
bus.get_signals = &get_signals;
res = ddc2_read_edid1( &bus, edid, &vdif, &vdif_len );
if( res != B_OK )
return false;
SHOW_FLOW( 2, "Found DDC-capable monitor @0x%04x", ddc_port );
if( vdif != NULL )
free( vdif );
return true;
}
// search for display connect to CRT DAC
// colour - true, if only a colour monitor is to be accepted
static bool Radeon_DetectCRTInt( accelerator_info *ai, bool colour )
{
vuint8 *regs = ai->regs;
uint32 old_crtc_ext_cntl, old_dac_ext_cntl, old_dac_cntl, tmp;
bool found;
// makes sure there is a signal
old_crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL );
tmp = old_crtc_ext_cntl | RADEON_CRTC_CRT_ON;
OUTREG( regs, RADEON_CRTC_EXT_CNTL, tmp );
// force DAC to output constant voltage
// for colour monitors, RGB is tested, for B/W only G
old_dac_ext_cntl = INREG( regs, RADEON_DAC_EXT_CNTL );
tmp =
RADEON_DAC_FORCE_BLANK_OFF_EN |
RADEON_DAC_FORCE_DATA_EN |
(colour ? RADEON_DAC_FORCE_DATA_SEL_RGB : RADEON_DAC_FORCE_DATA_SEL_G) |
(0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
OUTREG( regs, RADEON_DAC_EXT_CNTL, tmp );
// enable DAC and tell is to use VGA signals
old_dac_cntl = INREG( regs, RADEON_DAC_CNTL );
tmp = old_dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN);
tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN;
OUTREG( regs, RADEON_DAC_CNTL, tmp );
// specs says that we should wait 1µs before checking but sample
// code uses 2 ms; we use long delay to be on safe side
// (though we don't want to make it too long as the monitor
// gets no sync signal now)
snooze( 2000 );
// let's see whether there is some
found = (INREG( regs, RADEON_DAC_CNTL ) & RADEON_DAC_CMP_OUTPUT) != 0;
if( found )
SHOW_INFO( 2, "Found %s CRT connected to CRT-DAC", colour ? "colour" : "b/w" );
OUTREG( regs, RADEON_DAC_CNTL, old_dac_cntl );
OUTREG( regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl );
OUTREG( regs, RADEON_CRTC_EXT_CNTL, old_crtc_ext_cntl );
return found;
}
// check whethere there is a CRT connected to CRT DAC
static bool Radeon_DetectCRT( accelerator_info *ai )
{
vuint32 old_vclk_ecp_cntl, tmp;
bool found;
// enforce clock so the DAC gets activated
old_vclk_ecp_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL );
tmp = old_vclk_ecp_cntl &
~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb);
Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, tmp );
// search first for colour, then for B/W monitor
found = Radeon_DetectCRTInt( ai, true ) || Radeon_DetectCRTInt( ai, false );
Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, old_vclk_ecp_cntl );
return found;
}
// CRT on TV-DAC detection for rv200 and below
// checked for rv200
static bool Radeon_DetectTVCRT_RV200( accelerator_info *ai )
{
vuint8 *regs = ai->regs;
uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, tmp;
bool found;
// enable CRTC2, setting 8 bpp (we just pick any valid value)
old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL );
tmp = old_crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK;
tmp |=
RADEON_CRTC2_CRT2_ON |
(2 << RADEON_CRTC2_PIX_WIDTH_SHIFT);
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, tmp );
// enable TV-DAC, choosing VGA signal level
old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL );
tmp =
RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_DETECT |
RADEON_TV_DAC_CNTL_STD_PS2;
OUTREG( regs, RADEON_TV_DAC_CNTL, tmp );
// enforce constant DAC output voltage on RGB
tmp =
RADEON_DAC2_FORCE_BLANK_OFF_EN |
RADEON_DAC2_FORCE_DATA_EN |
RADEON_DAC_FORCE_DATA_SEL_RGB |
(0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
OUTREG( regs, RADEON_DAC_EXT_CNTL, tmp );
old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 );
// set DAC in CRT mode and enable detection
// TODO: make sure we really use CRTC2 - this is ASIC dependant
tmp = old_dac_cntl2 | RADEON_DAC2_CLK_SEL_CRT | RADEON_DAC2_CMP_EN;
OUTREG( regs, RADEON_DAC_CNTL2, tmp );
snooze( 10000 );
// let's see what we've got!
found = (INREG( regs, RADEON_DAC_CNTL2 ) & RADEON_DAC2_CMP_OUTPUT) != 0;
if( found )
SHOW_INFO0( 2, "Found CRT connected to TV-DAC, i.e. DVI port" );
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
OUTREG( regs, RADEON_DAC_EXT_CNTL, 0 );
OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl );
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
return found;
}
// CRT on TV-DAC detection for r300
// checked for r300
static bool Radeon_DetectTVCRT_R300( accelerator_info *ai )
{
vuint8 *regs = ai->regs;
uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, tmp;
bool found;
// whatever these flags mean - let's pray they won't get changed
OUTREGP( regs, RADEON_GPIOPAD_EN, 1, ~1 );
OUTREGP( regs, RADEON_GPIOPAD_MASK, 1, ~1 );
OUTREGP( regs, RADEON_GPIOPAD_A, 1, ~1 );
old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL );
// enable DAC, choose valid pixel format and enable DPMS
// as usual, the code doesn't take into account whether the TV-DAC
// does really use CRTC2
tmp = old_crtc2_gen_cntl;
tmp &= ~RADEON_CRTC2_PIX_WIDTH_MASK;
tmp |=
(2 << RADEON_CRTC2_PIX_WIDTH_SHIFT) |
RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT;
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, tmp );
old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL );
// enable TV-DAC
OUTREG( regs, RADEON_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_DETECT |
RADEON_TV_DAC_CNTL_STD_PS2 );
// force constant voltage output of DAC for impedance test
OUTREG( regs, RADEON_DAC_EXT_CNTL,
RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN |
RADEON_DAC_FORCE_DATA_SEL_RGB |
(0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT ));
old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 );
// enable CRT mode of TV-DAC and enable comparator
tmp = old_dac_cntl2 | RADEON_DAC2_CLK_SEL_CRT | RADEON_DAC2_CMP_EN;
OUTREG( regs, RADEON_DAC_CNTL2, tmp );
snooze( 10000 );
// check connection of blue data signal to see whether there is a CRT
found = (INREG( regs, RADEON_DAC_CNTL2 ) & RADEON_DAC2_CMP_OUT_B) != 0;
// clean up the mess
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
OUTREG( regs, RADEON_DAC_EXT_CNTL, 0 );
OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl );
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
return found;
}
// check whether there is a CRT connected to TV-DAC
static bool Radeon_DetectTVCRT( accelerator_info *ai )
{
switch( ai->si->asic ) {
case rt_r100:
case rt_m6:
case rt_m7:
// original Radeons have pure DVI only and mobility chips
// have no DVI connector
// TBD: can they have a docking station for CRT on TV-DAC?
return dd_none;
case rt_ve:
case rt_rv200:
case rt_rv250:
case rt_rv280:
return Radeon_DetectTVCRT_RV200( ai );
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
return Radeon_DetectTVCRT_R300( ai );
default:
// don't know about IGP
;
}
return dd_none;
}
// TV detection for rv200 and below
// should work for M6 and RV200
static display_device_e Radeon_DetectTV_RV200( accelerator_info *ai, bool tv_crt_found )
{
vuint8 *regs = ai->regs;
uint32
tmp, old_dac_cntl2, old_crtc_ext_cntl, old_crtc2_gen_cntl, old_tv_master_cntl,
old_tv_dac_cntl, old_pre_dac_mux_cntl, config_cntl;
display_device_e displays = dd_none;
// give up if there is a CRT connected to TV-DAC
if( tv_crt_found )
return dd_none;
// enable TV mode
old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 );
tmp = old_dac_cntl2 & ~RADEON_DAC2_CLK_SEL_CRT;
OUTREG( regs, RADEON_DAC_CNTL2, tmp );
old_crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL );
old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL );
old_tv_master_cntl = INREG( regs, RADEON_TV_MASTER_CNTL );
// enable TV output
tmp = old_tv_master_cntl | RADEON_TV_MASTER_CNTL_TV_ON;
tmp &= ~(
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX |
RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN |
RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN |
RADEON_TV_MASTER_CNTL_RE_SYNC_NOW_SEL_MASK);
tmp |=
RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST;
OUTREG( regs, RADEON_TV_MASTER_CNTL, tmp );
old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL );
config_cntl = INREG( regs, RADEON_CONFIG_CNTL );
// unlock TV DAC
tmp =
RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_STD_NTSC |
(8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) |
((((config_cntl & RADEON_CFG_ATI_REV_ID_MASK) == 0) ? 8 : 4) << RADEON_TV_DAC_CNTL_DACADJ_SHIFT);
OUTREG( regs, RADEON_TV_DAC_CNTL, tmp );
old_pre_dac_mux_cntl = INREG( regs, RADEON_TV_PRE_DAC_MUX_CNTL );
// force constant DAC output voltage
tmp =
RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN |
(RADEON_TV_MUX_FORCE_DAC_DATA << RADEON_TV_PRE_DAC_MUX_CNTL_RED_MX_SHIFT) |
(RADEON_TV_MUX_FORCE_DAC_DATA << RADEON_TV_PRE_DAC_MUX_CNTL_GRN_MX_SHIFT) |
(RADEON_TV_MUX_FORCE_DAC_DATA << RADEON_TV_PRE_DAC_MUX_CNTL_BLU_MX_SHIFT) |
(0x109 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);
OUTREG( regs, RADEON_TV_PRE_DAC_MUX_CNTL, tmp );
// let things settle a bit
snooze( 3000 );
// now see which wires are connected
tmp = INREG( regs, RADEON_TV_DAC_CNTL );
if( (tmp & RADEON_TV_DAC_CNTL_GDACDET) != 0 ) {
displays |= dd_stv;
SHOW_INFO0( 2, "S-Video TV-Out is connected" );
}
if( (tmp & RADEON_TV_DAC_CNTL_BDACDET) != 0 ) {
displays |= dd_ctv;
SHOW_INFO0( 2, "Composite TV-Out is connected" );
}
OUTREG( regs, RADEON_TV_PRE_DAC_MUX_CNTL, old_pre_dac_mux_cntl );
OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl );
OUTREG( regs, RADEON_TV_MASTER_CNTL, old_tv_master_cntl );
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
OUTREG( regs, RADEON_CRTC_EXT_CNTL, old_crtc_ext_cntl );
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
return displays;
}
// TV detection for r300 series
// should work for R300
static display_device_e Radeon_DetectTV_R300( accelerator_info *ai )
{
vuint8 *regs = ai->regs;
display_device_e displays = dd_none;
uint32 tmp, old_dac_cntl2, old_crtc2_gen_cntl, old_dac_ext_cntl, old_tv_dac_cntl;
// whatever these flags mean - let's pray they won't get changed
OUTREGP( regs, RADEON_GPIOPAD_EN, 1, ~1 );
OUTREGP( regs, RADEON_GPIOPAD_MASK, 1, ~1 );
OUTREGP( regs, RADEON_GPIOPAD_A, 0, ~1 );
old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 );
// set CRT mode (!) of TV-DAC
OUTREG( regs, RADEON_DAC_CNTL2, RADEON_DAC2_CLK_SEL_CRT );
old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL );
// enable TV-Out output, but set DPMS mode
// (this seems to be not correct if TV-Out is connected to CRTC1,
// but it doesn't really hurt having wrong DPMS mode)
OUTREG( regs, RADEON_CRTC2_GEN_CNTL,
RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT );
old_dac_ext_cntl = INREG( regs, RADEON_DAC_EXT_CNTL );
// force constant voltage output of DAC for impedance test
OUTREG( regs, RADEON_DAC_EXT_CNTL,
RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN |
RADEON_DAC_FORCE_DATA_SEL_RGB |
(0xec << RADEON_DAC_FORCE_DATA_SHIFT ));
old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL );
// get TV-DAC running (or something...)
OUTREG( regs, RADEON_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_STD_NTSC |
(8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) |
(6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT ));
(void)INREG( regs, RADEON_TV_DAC_CNTL );
snooze( 4000 );
OUTREG( regs, RADEON_TV_DAC_CNTL,
RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_DETECT |
RADEON_TV_DAC_CNTL_STD_NTSC |
(8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) |
(6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT ));
(void)INREG( regs, RADEON_TV_DAC_CNTL );
snooze( 6000 );
// now see which wires are connected
tmp = INREG( regs, RADEON_TV_DAC_CNTL );
if( (tmp & RADEON_TV_DAC_CNTL_GDACDET) != 0 ) {
displays |= dd_stv;
SHOW_INFO0( 2, "S-Video TV-Out is connected" );
}
if( (tmp & RADEON_TV_DAC_CNTL_BDACDET) != 0 ) {
displays |= dd_ctv;
SHOW_INFO0( 2, "Composite TV-Out is connected" );
}
// clean up the mess we did
OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl );
OUTREG( regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl );
OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl );
OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 );
// again the magic wire
// !if you uncomment this, TV-out gets disabled
//OUTREGP( regs, RADEON_GPIOPAD_A, 1, ~1 );
return displays;
}
// check whether there is a TV connected to TV-DAC
// returns bit set, i.e. there can be S-Video or composite or both
static display_device_e Radeon_DetectTV( accelerator_info *ai, bool tv_crt_found )
{
switch( ai->si->asic ) {
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
return Radeon_DetectTV_RV200( ai, tv_crt_found );
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
return Radeon_DetectTV_R300( ai );
default:
// don't know about IGP
;
}
return dd_none;
}
// read edid data of flat panel and setup its timing accordingly
static status_t Radeon_StoreFPEDID( accelerator_info *ai, edid1_info *edid )
{
fp_info *fp = &ai->si->flatpanels[0];
uint32 max_hsize, max_vsize;
int i;
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;
}
// detect connected displays devices
// whished_num_heads - how many heads the requested display mode needs
void Radeon_DetectDisplays( accelerator_info *ai )
{
shared_info *si = ai->si;
display_device_e displays = 0;
edid1_info edid;
// mobile chips are for use in laptops - there must be a laptop panel
if( si->is_mobility )
displays |= dd_lvds;
// use DDC to detect monitors - if we can read DDC, there must be a monitor
// all non-mobility versions have a DVI port
if( (displays & dd_lvds) == 0 &&
Radeon_ReadEDID( ai, RADEON_GPIO_DVI_DDC, &edid ))
{
SHOW_FLOW0( 2, "Found monitor on DVI DDC port" );
// there may be an analog monitor connected to DVI-I;
// we must check EDID to see whether it's really a digital monitor
if( edid.display.input_type == 1 ) {
SHOW_FLOW0( 2, "Must be a DVI monitor" );
// store info about DVI-connected flat-panel
if( Radeon_StoreFPEDID( ai, &edid ) == B_OK ) {
displays |= dd_dvi;
} else {
SHOW_ERROR0( 2, "Disabled DVI - invalid EDID" );
}
} else {
// must be the analog portion of DVI
// I'm not sure about Radeons with one CRTC - do they have DVI-I or DVI-D?
// anyway - if there are two CRTC, analog portion must be connected
// to TV-DAC, if there is one CRTC, it must be the normal VGA-DAC
if( si->num_heads > 1 ) {
SHOW_FLOW0( 2, "Must be an analog monitor on DVI port" );
displays |= dd_tv_crt;
} else {
SHOW_FLOW0( 2, "Seems to be a CRT on VGA port!?" );
displays |= dd_crt;
}
}
}
// all chips have a standard VGA port
if( Radeon_ReadEDID( ai, RADEON_GPIO_VGA_DDC, &edid ))
displays |= dd_crt;
// we may have overseen monitors if they don't support DDC or
// have broken DDC data (like mine);
// time to do a physical wire test; this test is more reliable, but it
// leads to distortions on screen, which is not very nice to look at
// for DVI, there is no mercy if no DDC data is there - we wouldn't
// even know the native resolution of the panel!
// all versions have a standard VGA port
if( (displays & dd_crt) == 0 &&
Radeon_DetectCRT( ai ))
displays |= dd_crt;
// check VGA signal routed to DVI port
// (the detection code checks whether there is hardware for that)
if( (displays & dd_tv_crt) == 0 &&
Radeon_DetectTVCRT( ai ))
displays |= dd_tv_crt;
// TV-Out doesn't work, so don't detect that
#if 0
// check TV-out connector
// (this is the only one where we cannot use DDC)
displays |= Radeon_DetectTV( ai, (displays & dd_tv_crt) != 0 );
#endif
SHOW_INFO( 0, "Detected monitors: 0x%x", displays );
// if no monitor found, we define to have a CRT connected to CRT-DAC
if( displays == 0 )
displays = dd_crt;
si->connected_displays = displays;
}
@@ -0,0 +1,301 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
CRTC <-> display routing
*/
#include "radeon_accelerant.h"
#include "mmio.h"
#include "dac_regs.h"
#include "fp_regs.h"
#include "crtc_regs.h"
#include "tv_out_regs.h"
// read regs needed for display device routing
void Radeon_ReadMonitorRoutingRegs( accelerator_info *ai, physical_head *head,
port_regs *values )
{
vuint8 *regs = ai->regs;
(void)head;
values->dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 );
values->crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL );
values->disp_output_cntl = INREG( regs, RADEON_DISP_OUTPUT_CNTL );
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
values->disp_hw_debug = INREG( regs, RADEON_DISP_HW_DEBUG );
}
if( ai->si->asic > rt_r100 ) {
// register introduced after R100
values->tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL );
}
values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL );
values->fp2_gen_cntl = INREG( regs, RADEON_FP2_GEN_CNTL );
}
// setup register contents to proper CRTC <-> display device mapping
void Radeon_CalcMonitorRouting( accelerator_info *ai, physical_head *head,
port_regs *values )
{
display_device_e display_devices;
display_devices = head->chosen_displays;
// route VGA-DAC
if( (display_devices & dd_crt) != 0 ) {
// the CRT_ON flag seems to directly affect the CRT-DAC, _not_ the CRTC1 signal
values->crtc_ext_cntl |= RADEON_CRTC_CRT_ON;
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
values->disp_output_cntl =
(values->disp_output_cntl & ~RADEON_DISP_DAC_SOURCE_MASK) |
(head->is_crtc2 ? RADEON_DISP_DAC_SOURCE_CRTC2 : 0);
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
values->dac_cntl2 &= ~RADEON_DAC_CLK_SEL_MASK;
values->dac_cntl2 |= head->is_crtc2 ? RADEON_DAC_CLK_SEL_CRTC2 : 0;
}
}
// set CRT mode of TV-DAC if needed
if( (display_devices & dd_tv_crt) != 0 ) {
// TODO: this register doesn't exist on r200 as TV DAC is on
// external Rage Theatre
values->dac_cntl2 &= ~RADEON_DAC2_CLK_SEL_MASK;
values->dac_cntl2 |= RADEON_DAC2_CLK_SEL_CRT;
// enable TV-DAC
values->tv_dac_cntl =
RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_STD_PS2;
}
// set TV mode of TV-DAC if needed
if( (display_devices & (dd_ctv | dd_stv)) != 0 ) {
// see above
values->dac_cntl2 &= ~RADEON_DAC2_CLK_SEL_MASK;
values->dac_cntl2 |= RADEON_DAC2_CLK_SEL_TV;
}
// choose CRTC for TV-DAC
if( (display_devices & (dd_tv_crt | dd_ctv | dd_stv)) != 0 ) {
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
// for r200, this register doesn not exist!?
// according to r300 spec, this is because TV-DAC is on external chip
values->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
values->disp_output_cntl |=
head->is_crtc2 ? RADEON_DISP_TVDAC_SOURCE_CRTC2 : 0;
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
values->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
values->disp_hw_debug |= head->is_crtc2 ? RADEON_CRT2_DISP1_SEL : 0;
}
}
// choose CRTC for flat panel
if( (display_devices & (dd_lvds | dd_dvi)) != 0 ) {
values->fp_gen_cntl |= head->is_crtc2 ? RADEON_FP_SEL_CRTC2 : 0;
}
// enable/disable RMX for crtc1
// (TODO: this doesn't seem to work)
// !!! makes trouble on Radeon 9200 Mobility !??
/*
if( !head->is_crtc2 ) {
// use RMX if there is a flat panel
if( (display_devices & (dd_lvds | dd_dvi)) != 0 ) {
values->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
values->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_RMX;
}
}*/
// choose CRTC for secondary flat panel
if( (display_devices & dd_dvi_ext) != 0 ) {
// TODO: this list looks a bit magic/wrong for me; I reckon ATI moved the
// bit starting with ASIC xxx, but I have no specs to verify that
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r350:
case rt_rv350:
values->fp2_gen_cntl |=
head->is_crtc2 ? RADEON_FP2_SOURCE_SEL_CRTC2 : 0;
break;
default:
values->fp2_gen_cntl |=
head->is_crtc2 ? RADEON_FP2_SRC_SEL_CRTC2 : 0;
}
}
// we don't set source of TV-OUT unit - it's done in the tv-out code
}
void Radeon_ProgramMonitorRouting( accelerator_info *ai, physical_head *head, port_regs *values )
{
vuint8 *regs = ai->regs;
(void)head;
OUTREG( regs, RADEON_DAC_CNTL2, values->dac_cntl2 );
OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl,
~RADEON_CRTC_CRT_ON );
OUTREG( regs, RADEON_DISP_OUTPUT_CNTL, values->disp_output_cntl );
switch( ai->si->asic ) {
case rt_r200:
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
break;
case rt_ve:
case rt_m6:
case rt_rv200:
case rt_m7:
case rt_rv250:
case rt_rv280:
case rt_m9:
default:
OUTREG( regs, RADEON_DISP_HW_DEBUG, values->disp_hw_debug );
}
if( ai->si->asic > rt_r100 ) {
// register introduced after R100
OUTREG( regs, RADEON_TV_DAC_CNTL, values->tv_dac_cntl );
}
OUTREG( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl );
OUTREG( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl );
}
// Setup sensible default monitor routing
// whished_num_heads - number of independant heads current display mode would need
void Radeon_SetupDefaultMonitorRouting( accelerator_info *ai, int whished_num_heads )
{
display_device_e crtc1_displays = 0, crtc2_displays = 0;
display_device_e display_devices = ai->si->connected_displays;
// flat panels get always connected to CRTC1 because its RMX unit
if( (display_devices & dd_lvds) != 0 ) {
// don't enable Laptop panel if display mode needs one head only
// and there is a CRT connected (showing the same on both panel and
// CRT doesn't make much sense)
if( !(whished_num_heads == 1 && (display_devices & (dd_crt | dd_tv_crt)) != 0 ))
crtc1_displays |= dd_lvds;
} else if( (display_devices & dd_dvi) != 0 )
crtc1_displays |= dd_dvi;
// TV-Out gets always connected to crtc2...
if( (display_devices & dd_stv) != 0 )
crtc2_displays |= dd_stv;
else if( (display_devices & dd_stv) != 0 )
crtc2_displays |= dd_ctv;
// ...but if there is no crtc2, they win on crtc1;
// if the user connects both a flat panel and a TV, he certainly wants to use the TV
if( ai->si->num_heads == 1 && crtc2_displays != 0 )
crtc1_displays = crtc2_displays;
// if TV-Out is used, the DAC cannot drive a CRT at the same time
if( (display_devices & (dd_stv | dd_ctv)) != 0 )
display_devices &= ~dd_tv_crt;
// CRT on CRT-DAC gets any spare CRTC;
// if there is none, it can share CRTC with TV-Out
if( (display_devices & dd_crt) != 0 ) {
if( crtc1_displays == 0 )
crtc1_displays |= dd_crt;
else if( ai->si->num_heads > 1 && crtc2_displays == 0 )
crtc2_displays |= dd_crt;
else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 )
crtc1_displays |= dd_crt;
else if( ai->si->num_heads > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 )
crtc2_displays |= dd_crt;
}
// same applies to CRT on TV-DAC;
// if we cannot find a CRTC, we could clone the content of the CRT-DAC,
// but I doubt that you really want two CRTs showing the same
if( (display_devices & dd_tv_crt) != 0 &&
(display_devices & (dd_ctv | dd_stv)) == 0 )
{
if( crtc1_displays == 0 )
crtc1_displays |= dd_tv_crt;
else if( ai->si->num_heads > 1 && crtc2_displays == 0 )
crtc2_displays |= dd_tv_crt;
else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 )
crtc1_displays |= dd_tv_crt;
else if( ai->si->num_heads > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 )
crtc2_displays |= dd_tv_crt;
}
//crtc1_displays = dd_stv | dd_crt;
//crtc2_displays = 0;
SHOW_FLOW( 2, "CRTC1: 0x%x, CRTC2: 0x%x", crtc1_displays, crtc2_displays );
ai->si->heads[0].chosen_displays = crtc1_displays;
ai->si->heads[1].chosen_displays = crtc2_displays;
}
+19 -26
View File
@@ -15,8 +15,6 @@
// 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 ) {
@@ -33,12 +31,6 @@ void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
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
@@ -73,7 +65,7 @@ void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
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;
mode->flags |= B_SCROLL;
}
}
@@ -82,9 +74,9 @@ void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mo
{
// 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) )
if( vc->num_heads == 1 ||
(si->heads[vc->heads[0].physical_head].chosen_displays == dd_none ||
si->heads[vc->heads[1].physical_head].chosen_displays == dd_none) )
{
SHOW_FLOW0( 3, "only one monitor - disabling any multi-mon mode" );
// restore flags if combine mode is selected
@@ -100,6 +92,8 @@ void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mo
// to official mode
void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
{
(void) vc;
// restore flags for combine mode
if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
mode->flags |= B_SCROLL;
@@ -109,21 +103,20 @@ void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
// 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;
vc->heads[0].rel_x = 0;
vc->heads[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;
vc->heads[1].rel_x = 0;
vc->heads[1].rel_y = 0;
break;
case RADEON_MODE_COMBINE:
@@ -141,16 +134,16 @@ void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode )
SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
vc->ports[1].rel_x = 0;
vc->ports[1].rel_y = 0;
vc->heads[1].rel_x = 0;
vc->heads[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;
if( !vc->swap_displays ) {
vc->heads[1].rel_x = x;
vc->heads[1].rel_y = y;
} else {
vc->ports[0].rel_x = x;
vc->ports[0].rel_y = y;
vc->heads[0].rel_x = x;
vc->heads[0].rel_y = y;
}
break;
@@ -195,9 +188,9 @@ status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
switch( mode->h_display_start ) {
case ms_swap:
if( mode->v_display_start != 0 )
vc->swapDisplays = mode->timing.flags != 0;
vc->swap_displays = mode->timing.flags != 0;
else
mode->timing.flags = vc->swapDisplays;
mode->timing.flags = vc->swap_displays;
// write settings instantly
Radeon_WriteSettings( vc );
+170 -126
View File
@@ -13,14 +13,11 @@
#include "overlay_regs.h"
#include "pll_regs.h"
#include "capture_regs.h"
#include "cp_regs.h"
#include "utils.h"
#include "pll_access.h"
#include <math.h>
#include <string.h>
void Radeon_InitOverlay( accelerator_info *ai, virtual_port *overlay_port );
status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port );
void Radeon_ReplaceOverlayBuffer( accelerator_info *ai );
#include "CP.h"
void Radeon_TempHideOverlay( accelerator_info *ai );
@@ -54,16 +51,14 @@ static struct {
// setup overlay unit before first use
void Radeon_InitOverlay( accelerator_info *ai, virtual_port *overlay_port )
void Radeon_InitOverlay( accelerator_info *ai, physical_head *head )
{
vuint8 *regs = ai->regs;
shared_info *si = ai->si;
uint i;
uint32 ecp_div;
SHOW_FLOW( 3, "physical_port=%d", overlay_port->physical_port );
Radeon_WaitForIdle( ai );
SHOW_FLOW0( 0, "" );
// make sure we really write this value as the "toggle" bit
// contained in it (which is zero initially) is edge-sensitive!
@@ -98,15 +93,15 @@ void Radeon_InitOverlay( accelerator_info *ai, virtual_port *overlay_port )
// overlay unit can only handle up to 175 MHz, if pixel clock is higher,
// only every second pixel is handled
if( overlay_port->mode.timing.pixel_clock < 175000 )
if( head->mode.timing.pixel_clock < 175000 )
ecp_div = 0;
else
ecp_div = 1;
Radeon_OUTPLLP( ai, RADEON_VCLK_ECP_CNTL,
Radeon_OUTPLLP( regs, si->asic, RADEON_VCLK_ECP_CNTL,
ecp_div << RADEON_ECP_DIV_SHIFT, ~RADEON_ECP_DIV_MASK );
si->active_overlay.port = si->pending_overlay.port;
si->active_overlay.head = si->pending_overlay.head;
// invalidate active colour space
si->active_overlay.ob.space = -1;
@@ -180,7 +175,7 @@ static void Radeon_SetTransform( accelerator_info *ai,
space_transform *trans;
SHOW_FLOW0( 3, "" );
SHOW_FLOW0( 0, "" );
// get proper conversion formula
switch( si->pending_overlay.ob.space ) {
@@ -305,28 +300,34 @@ static uint32 colourKey2RGB32( uint32 space, uint8 red, uint8 green, uint8 blue
// set colour key of overlay
void Radeon_SetColourKey( accelerator_info *ai, const overlay_window *ow )
static void Radeon_SetColourKey( accelerator_info *ai, const overlay_window *ow )
{
virtual_card *vc = ai->vc;
uint32 rgb32;
uint32 buffer[3*2];
uint idx = 0;
vuint8 *regs = ai->regs;
uint32 rgb32, mask32, min32, max32;
SHOW_FLOW0( 3, "" );
/*SHOW_FLOW( 0, "value=%02x %02x %02x, mask=%02x %02x %02x",
ow->red.value, ow->green.value, ow->blue.value,
ow->red.mask, ow->green.mask, ow->blue.mask );*/
// Radeons don't support value and mask as colour key but colour range
rgb32 = colourKey2RGB32( vc->mode.space,
ow->red.value, ow->green.value, ow->blue.value );
mask32 = colourKey2RGB32( vc->mode.space,
ow->red.mask, ow->green.mask, ow->blue.mask );
// ~mask32 are all unimportant (usually low order) bits
// oring this to the colour should give us the highest valid colour value
// (add would be more precise but may lead to overflows)
min32 = rgb32;
max32 = rgb32 | ~mask32;
buffer[idx++] = CP_PACKET0( RADEON_OV0_GRAPHICS_KEY_CLR_LOW, 0 );
buffer[idx++] = rgb32;
buffer[idx++] = CP_PACKET0( RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, 0 );
buffer[idx++] = rgb32;
buffer[idx++] = CP_PACKET0( RADEON_OV0_KEY_CNTL, 0 );
buffer[idx++] = RADEON_GRAPHIC_KEY_FN_EQ |
OUTREG( regs, RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min32 );
OUTREG( regs, RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, max32 );
OUTREG( regs, RADEON_OV0_KEY_CNTL,
RADEON_GRAPHIC_KEY_FN_EQ |
RADEON_VIDEO_KEY_FN_FALSE |
RADEON_CMP_MIX_OR;
Radeon_SendCP( ai, buffer, idx );
RADEON_CMP_MIX_OR );
}
typedef struct {
@@ -510,16 +511,16 @@ static hscale_factor *getHScaleFactor( space_params *params,
// show overlay on screen
status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port )
static status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_head *virtual_head )
{
virtual_card *vc = ai->vc;
// vuint8 *regs = ai->regs;
shared_info *si = ai->si;
vuint8 *regs = ai->regs;
overlay_info *overlay = &si->pending_overlay;
overlay_buffer_node *node = overlay->on;
physical_head *head = &si->heads[virtual_head->physical_head];
uint32 ecp_div;
// uint32 step_by;
uint32 v_inc, h_inc;
uint32 src_v_inc, src_h_inc;
uint32 src_left, src_top, src_right, src_bottom;
@@ -535,18 +536,18 @@ status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port )
uint32 p1_x_start, p1_x_end;
uint32 p23_x_start, p23_x_end;
uint32 buffer[20*2];
uint idx = 0;
/*uint32 buffer[20*2];
uint idx = 0;*/
SHOW_FLOW0( 3, "" );
SHOW_FLOW0( 0, "" );
Radeon_SetColourKey( ai, &overlay->ow );
// overlay unit can only handle up to 175 MHz; if pixel clock is higher,
// only every second pixel is handled
// (this devider is gets written into PLL by OverlayInit,
// (this devider is gets written into PLL by InitOverlay,
// so we don't need to do it ourself)
if( overlay_port->mode.timing.pixel_clock < 175000 )
if( head->mode.timing.pixel_clock < 175000 )
ecp_div = 0;
else
ecp_div = 1;
@@ -594,10 +595,10 @@ status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port )
// apply virtual screen
dest_left -= vc->mode.h_display_start + overlay_port->rel_x;
dest_top -= vc->mode.v_display_start + overlay_port->rel_y;
dest_right -= vc->mode.h_display_start + overlay_port->rel_x;
dest_bottom -= vc->mode.v_display_start + overlay_port->rel_y;
dest_left -= vc->mode.h_display_start + virtual_head->rel_x;
dest_top -= vc->mode.v_display_start + virtual_head->rel_y;
dest_right -= vc->mode.h_display_start + virtual_head->rel_x;
dest_bottom -= vc->mode.v_display_start + virtual_head->rel_y;
// clip to visible area
@@ -611,12 +612,12 @@ status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port )
}
SHOW_FLOW( 3, "mode: w=%d, h=%d",
overlay_port->mode.timing.h_display, overlay_port->mode.timing.v_display );
head->mode.timing.h_display, head->mode.timing.v_display );
if( dest_right > overlay_port->mode.timing.h_display )
dest_right = overlay_port->mode.timing.h_display;
if( dest_bottom > overlay_port->mode.timing.v_display )
dest_bottom = overlay_port->mode.timing.v_display;
if( dest_right > head->mode.timing.h_display )
dest_right = head->mode.timing.h_display;
if( dest_bottom > head->mode.timing.v_display )
dest_bottom = head->mode.timing.v_display;
SHOW_FLOW( 3, "src=(%d, %d, %d, %d)",
src_left, src_top, src_right, src_bottom );
@@ -717,16 +718,16 @@ status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port )
// TBD: there is no description at all concerning this, so v_accum_init may
// need to be initialized based on original value
{
display_type_e disp_type;
display_device_e disp_devices;
disp_type = si->ports[overlay_port->physical_port].disp_type;
if( disp_type == dt_lvds || disp_type == dt_dvi_1 ) {
disp_devices = head->active_displays;
if( (disp_devices & (dd_lvds | dd_dvi)) != 0 ) {
uint64 v_ratio;
// convert 32.32 format to 16.16 format; else we
// cannot multiply two fixed point values without
// overflow
v_ratio = si->fp_port.v_ratio >> (FIX_SHIFT - 16);
v_ratio = si->flatpanels[head->flatpanel_port].v_ratio >> (FIX_SHIFT - 16);
v_inc = (v_inc * v_ratio) >> 16;
}
@@ -826,61 +827,61 @@ status_t Radeon_ShowOverlay( accelerator_info *ai, virtual_port *overlay_port )
// but during tests I couldn't get the artifacts go away, so
// we use the dangerous way which has the pro to not require any
// waiting
buffer[idx++] = CP_PACKET0( RADEON_OV0_VID_BUF0_BASE_ADRS, 0 );
buffer[idx++] = offset;
buffer[idx++] = CP_PACKET0( RADEON_OV0_VID_BUF_PITCH0_VALUE, 0 );
buffer[idx++] = node->buffer.bytes_per_row;
buffer[idx++] = CP_PACKET0( RADEON_OV0_H_INC, 0 );
buffer[idx++] = p1_h_inc | (p23_h_inc << 16);
buffer[idx++] = CP_PACKET0( RADEON_OV0_STEP_BY, 0 );
buffer[idx++] = factors->p1_step_by | (factors->p23_step_by << 8);
buffer[idx++] = CP_PACKET0( RADEON_OV0_V_INC, 0 );
buffer[idx++] = v_inc;
// let's try to lock overlay unit
// we had to wait now until the lock takes effect, but this is
// impossible with CCE; perhaps we have to convert this code to
// direct register access; did that - let's see what happens...
OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK );
buffer[idx++] = CP_PACKET0(
overlay_port->is_crtc2 ? RADEON_OV1_Y_X_START : RADEON_OV0_Y_X_START, 0 );
buffer[idx++] = (dest_left) | (dest_top << 16);
buffer[idx++] = CP_PACKET0(
overlay_port->is_crtc2 ? RADEON_OV1_Y_X_END : RADEON_OV0_Y_X_END, 0 );
buffer[idx++] = (dest_right - 1) | ((dest_bottom - 1) << 16);
// wait until register access is locked
while( (INREG( regs, RADEON_OV0_REG_LOAD_CNTL)
& RADEON_REG_LD_CTL_LOCK_READBACK) == 0 )
;
OUTREG( regs, RADEON_OV0_VID_BUF0_BASE_ADRS, offset );
OUTREG( regs, RADEON_OV0_VID_BUF_PITCH0_VALUE, node->buffer.bytes_per_row );
OUTREG( regs, RADEON_OV0_H_INC, p1_h_inc | (p23_h_inc << 16) );
OUTREG( regs, RADEON_OV0_STEP_BY, factors->p1_step_by | (factors->p23_step_by << 8) );
OUTREG( regs, RADEON_OV0_V_INC, v_inc );
OUTREG( regs,
head->is_crtc2 ? RADEON_OV1_Y_X_START : RADEON_OV0_Y_X_START,
(dest_left) | (dest_top << 16) );
OUTREG( regs,
head->is_crtc2 ? RADEON_OV1_Y_X_END : RADEON_OV0_Y_X_END,
(dest_right - 1) | ((dest_bottom - 1) << 16) );
buffer[idx++] = CP_PACKET0( RADEON_OV0_P1_BLANK_LINES_AT_TOP, 0 );
buffer[idx++] = RADEON_P1_BLNK_LN_AT_TOP_M1_MASK | (p1_active_lines << 16);
buffer[idx++] = CP_PACKET0( RADEON_OV0_P1_X_START_END, 0 );
buffer[idx++] = p1_x_end | (p1_x_start << 16);
buffer[idx++] = CP_PACKET0( RADEON_OV0_P1_H_ACCUM_INIT, 0 );
buffer[idx++] = p1_h_accum_init;
buffer[idx++] = CP_PACKET0( RADEON_OV0_P1_V_ACCUM_INIT, 0 );
buffer[idx++] = p1_v_accum_init;
OUTREG( regs, RADEON_OV0_P1_BLANK_LINES_AT_TOP,
RADEON_P1_BLNK_LN_AT_TOP_M1_MASK | (p1_active_lines << 16) );
OUTREG( regs, RADEON_OV0_P1_X_START_END, p1_x_end | (p1_x_start << 16) );
OUTREG( regs, RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init );
OUTREG( regs, RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init );
buffer[idx++] = CP_PACKET0( RADEON_OV0_P23_BLANK_LINES_AT_TOP, 0 );
buffer[idx++] = RADEON_P23_BLNK_LN_AT_TOP_M1_MASK | (p23_active_lines << 16);
buffer[idx++] = CP_PACKET0( RADEON_OV0_P2_X_START_END, 0 );
buffer[idx++] = p23_x_end | (p23_x_start << 16);
buffer[idx++] = CP_PACKET0( RADEON_OV0_P3_X_START_END, 0 );
buffer[idx++] = p23_x_end | (p23_x_start << 16);
buffer[idx++] = CP_PACKET0( RADEON_OV0_P23_H_ACCUM_INIT, 0 );
buffer[idx++] = p23_h_accum_init;
buffer[idx++] = CP_PACKET0( RADEON_OV0_P23_V_ACCUM_INIT, 0 );
buffer[idx++] = p23_v_accum_init;
OUTREG( regs, RADEON_OV0_P23_BLANK_LINES_AT_TOP,
RADEON_P23_BLNK_LN_AT_TOP_M1_MASK | (p23_active_lines << 16) );
OUTREG( regs, RADEON_OV0_P2_X_START_END,
p23_x_end | (p23_x_start << 16) );
OUTREG( regs, RADEON_OV0_P3_X_START_END,
p23_x_end | (p23_x_start << 16) );
OUTREG( regs, RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init );
OUTREG( regs, RADEON_OV0_P23_V_ACCUM_INIT, p23_v_accum_init );
buffer[idx++] = CP_PACKET0( RADEON_OV0_TEST, 0 );
buffer[idx++] = node->test_reg;
buffer[idx++] = CP_PACKET0( RADEON_OV0_SCALE_CNTL, 0 );
buffer[idx++] = RADEON_SCALER_ENABLE |
OUTREG( regs, RADEON_OV0_TEST, node->test_reg );
OUTREG( regs, RADEON_OV0_SCALE_CNTL,
RADEON_SCALER_ENABLE |
RADEON_SCALER_DOUBLE_BUFFER |
(node->ati_space << 8) |
/*RADEON_SCALER_ADAPTIVE_DEINT |*/
(overlay_port->is_crtc2 ? RADEON_SCALER_CRTC_SEL : 0 );
(head->is_crtc2 ? RADEON_SCALER_CRTC_SEL : 0 ));
si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE;
buffer[idx++] = CP_PACKET0( RADEON_OV0_AUTO_FLIP_CNTRL, 0 );
buffer[idx++] = si->overlay_mgr.auto_flip_reg;
OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL,
si->overlay_mgr.auto_flip_reg );
OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 );
Radeon_SendCP( ai, buffer, idx );
done:
ai->si->active_overlay.on = ai->si->pending_overlay.on;
ai->si->active_overlay.ow = ai->si->pending_overlay.ow;
@@ -898,7 +899,7 @@ void Radeon_TempHideOverlay( accelerator_info *ai )
{
SHOW_FLOW0( 3, "" );
Radeon_WriteRegCP( ai, RADEON_OV0_SCALE_CNTL, 0 );
OUTREG( ai->regs, RADEON_OV0_SCALE_CNTL, 0 );
}
@@ -909,47 +910,88 @@ void Radeon_HideOverlay( accelerator_info *ai )
Radeon_TempHideOverlay( ai );
// save that there is no overlay to be shown
// remember that there is no overlay to be shown
si->active_overlay.on = NULL;
si->active_overlay.prev_on = NULL;
si->pending_overlay.on = NULL;
// invalidate active port so it will be setup again once
// invalidate active head so it will be setup again once
// a new overlay is shown
si->active_overlay.port = -1;
si->active_overlay.head = -1;
}
// show new overlay buffer with same parameters as last one
void Radeon_ReplaceOverlayBuffer( accelerator_info *ai )
static void Radeon_ReplaceOverlayBuffer( accelerator_info *ai )
{
#if 0
shared_info *si = ai->si;
// vuint8 *regs = ai->regs;
vuint8 *regs = ai->regs;
uint32 offset;
uint32 buffer[2*2];
uint idx = 0;
int /*old_buf, */new_buf;
offset = si->pending_overlay.on->mem_offset + si->active_overlay.rel_offset;
buffer[idx++] = CP_PACKET0( RADEON_OV0_VID_BUF0_BASE_ADRS, 0 );
buffer[idx++] = offset;
/*old_buf = si->overlay_mgr.auto_flip_reg & RADEON_OV0_SOFT_BUF_NUM_MASK;
new_buf = old_buf == 0 ? 3 : 0;
si->overlay_mgr.auto_flip_reg &= ~RADEON_OV0_SOFT_BUF_NUM_MASK;
si->overlay_mgr.auto_flip_reg |= new_buf;*/
new_buf = 0;
// lock overlay registers
/* OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK );
// wait until register access is locked
while( (INREG( regs, RADEON_OV0_REG_LOAD_CNTL)
& RADEON_REG_LD_CTL_LOCK_READBACK) == 0 )
;*/
// setup new buffer
/*OUTREG( regs,
new_buf == 0 ? RADEON_OV0_VID_BUF_PITCH0_VALUE : RADEON_OV0_VID_BUF_PITCH1_VALUE,
si->pending_overlay.on->buffer.bytes_per_row );*/
OUTREG( regs,
new_buf == 0 ? RADEON_OV0_VID_BUF0_BASE_ADRS : RADEON_OV0_VID_BUF3_BASE_ADRS,
offset | (new_buf == 0 ? 0 : RADEON_VIF_BUF0_PITCH_SEL));
// make changes visible
si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE;
buffer[idx++] = CP_PACKET0( RADEON_OV0_AUTO_FLIP_CNTRL, 0 );
buffer[idx++] = si->overlay_mgr.auto_flip_reg;
Radeon_SendCP( ai, buffer, idx );
OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg );
// unlock overlay registers
// OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 );
ai->si->active_overlay.on = ai->si->pending_overlay.on;
#else
shared_info *si = ai->si;
uint32 offset;
START_IB();
offset = si->pending_overlay.on->mem_offset + si->active_overlay.rel_offset;
WRITE_IB_REG( RADEON_OV0_VID_BUF0_BASE_ADRS, offset);
si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE;
WRITE_IB_REG( RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg );
SUBMIT_IB();
ai->si->active_overlay.on = ai->si->pending_overlay.on;
#endif
}
// get number of pixels of overlay shown on virtual port
static int getIntersectArea( virtual_card *vc, overlay_window *ow, virtual_port *port )
static int getIntersectArea( accelerator_info *ai, overlay_window *ow, virtual_head *virtual_head )
{
virtual_card *vc = ai->vc;
physical_head *head = &ai->si->heads[virtual_head->physical_head];
int left, top, right, bottom;
left = ow->h_start - (vc->mode.h_display_start + port->rel_x);
top = ow->v_start - (vc->mode.v_display_start + port->rel_y);
left = ow->h_start - (vc->mode.h_display_start + virtual_head->rel_x);
top = ow->v_start - (vc->mode.v_display_start + virtual_head->rel_y);
right = left + ow->width;
bottom = top + ow->height;
@@ -957,10 +999,10 @@ static int getIntersectArea( virtual_card *vc, overlay_window *ow, virtual_port
left = 0;
if( top < 0 )
top = 0;
if( right > port->mode.timing.h_display )
right = port->mode.timing.h_display;
if( bottom > port->mode.timing.v_display )
bottom = port->mode.timing.v_display;
if( right > head->mode.timing.h_display )
right = head->mode.timing.h_display;
if( bottom > head->mode.timing.v_display )
bottom = head->mode.timing.v_display;
if( right < left || bottom < top )
return 0;
@@ -975,7 +1017,8 @@ status_t Radeon_UpdateOverlay( accelerator_info *ai )
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
virtual_port *overlay_port;
virtual_head *virtual_head;
physical_head *physical_head;
float brightness = 0.0f;
float contrast = 1.0f;
@@ -1000,34 +1043,35 @@ status_t Radeon_UpdateOverlay( accelerator_info *ai )
/* SHOW_FLOW( 3, "num_ports=%d, whished_overlay_port=%d",
vc->num_ports, vc->whished_overlay_port );*/
if( vc->different_ports > 1 ) {
if( vc->different_heads > 1 ) {
int area0, area1;
// determine on which port most of the overlay is shown
area0 = getIntersectArea( vc, &si->pending_overlay.ow, &vc->ports[0] );
area1 = getIntersectArea( vc, &si->pending_overlay.ow, &vc->ports[1] );
area0 = getIntersectArea( ai, &si->pending_overlay.ow, &vc->heads[0] );
area1 = getIntersectArea( ai, &si->pending_overlay.ow, &vc->heads[1] );
SHOW_FLOW( 3, "area0=%d, area1=%d", area0, area1 );
if( area0 >= area1 )
overlay_port = &vc->ports[0];
virtual_head = &vc->heads[0];
else
overlay_port = &vc->ports[1];
virtual_head = &vc->heads[1];
} else {
// both ports show the same, use "swap displays" to decide
// where to show the overlay (to be improved as this flag isn't
// really designed for that)
if( vc->independant_ports > 1 && vc->swapDisplays )
overlay_port = &vc->ports[1];
if( vc->independant_heads > 1 && vc->swap_displays )
virtual_head = &vc->heads[1];
else
overlay_port = &vc->ports[0];
virtual_head = &vc->heads[0];
}
si->pending_overlay.port = overlay_port->physical_port;
si->pending_overlay.head = virtual_head->physical_head;
physical_head = &si->heads[virtual_head->physical_head];
// only update registers that have been changed to minimize work
if( si->active_overlay.port != si->pending_overlay.port ) {
Radeon_InitOverlay( ai, overlay_port );
if( si->active_overlay.head != si->pending_overlay.head ) {
Radeon_InitOverlay( ai, physical_head );
}
if( si->active_overlay.ob.space != si->pending_overlay.ob.space ) {
@@ -1041,7 +1085,7 @@ status_t Radeon_UpdateOverlay( accelerator_info *ai )
si->active_overlay.ob.width != si->pending_overlay.ob.width ||
si->active_overlay.ob.height != si->pending_overlay.ob.height ||
si->active_overlay.ob.bytes_per_row != si->pending_overlay.ob.bytes_per_row )
Radeon_ShowOverlay( ai, overlay_port );
Radeon_ShowOverlay( ai, virtual_head );
else if( si->active_overlay.on != si->pending_overlay.on )
Radeon_ReplaceOverlayBuffer( ai );
@@ -15,16 +15,6 @@
#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
@@ -39,6 +29,8 @@ uint32 OVERLAY_COUNT( const display_mode *dm )
{
SHOW_FLOW0( 3, "" );
(void) dm;
return 1;
}
@@ -48,6 +40,8 @@ uint32 OVERLAY_COUNT( const display_mode *dm )
const uint32 *OVERLAY_SUPPORTED_SPACES( const display_mode *dm )
{
SHOW_FLOW0( 3, "" );
(void) dm;
return overlay_colorspaces;
}
@@ -58,6 +52,8 @@ const uint32 *OVERLAY_SUPPORTED_SPACES( const display_mode *dm )
uint32 OVERLAY_SUPPORTED_FEATURES( uint32 color_space )
{
SHOW_FLOW0( 3, "" );
(void) color_space;
return
B_OVERLAY_COLOR_KEY |
@@ -73,7 +69,7 @@ const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uin
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
radeon_alloc_local_mem am;
radeon_alloc_mem am;
overlay_buffer_node *node;
overlay_buffer *buffer;
status_t result;
@@ -142,16 +138,18 @@ const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uin
am.magic = RADEON_PRIVATE_DATA_MAGIC;
am.size = buffer->bytes_per_row * height;
am.memory_type = mt_local;
am.global = false;
result = ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am );
result = ioctl( ai->fd, RADEON_ALLOC_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;
node->mem_offset = am.offset;
buffer->buffer = si->local_mem + am.offset;
buffer->buffer_dma = si->framebuffer_pci + am.offset;
// add to list of overlays
node->next = vc->overlay_buffers;
node->prev = NULL;
@@ -162,7 +160,8 @@ const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uin
RELEASE_BEN( si->engine.lock );
SHOW_FLOW( 3, "success: mem_handle=%x, offset=%x", node->mem_handle, node->mem_offset );
SHOW_FLOW( 0, "success: mem_handle=%x, offset=%x, CPU-address=%x, phys-address=%x",
node->mem_handle, node->mem_offset, buffer->buffer, buffer->buffer_dma );
return buffer;
@@ -178,20 +177,23 @@ 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;
radeon_free_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 )
if( si->active_overlay.on == node || si->active_overlay.prev_on )
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 );
fm.memory_type = mt_local;
fm.global = false;
result = ioctl( ai->fd, RADEON_FREE_MEM, &fm );
if( result != B_OK ) {
SHOW_FLOW( 3, "ups - couldn't free memory (handle=%x, status=%s)",
node->mem_handle, strerror( result ));
@@ -337,9 +339,8 @@ 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 )
+88
View File
@@ -0,0 +1,88 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
Palette handling. Though it's very often referred to as
being part of the DAC, this is not really true as palette
lookup is part of the CRTC unit (else it wouldn't work for
digital output like DVI)
*/
#include "GlobalData.h"
#include "dac_regs.h"
#include "CP.h"
// Radeon's DACs share same public registers, this function
// selects the DAC you'll talk to
#define selectPalette( head ) \
WRITE_IB_REG( RADEON_DAC_CNTL2, \
((head)->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)
void Radeon_InitPalette( accelerator_info *ai, physical_head *head )
{
int i;
START_IB();
selectPalette( head );
WRITE_IB_REG( RADEON_PALETTE_INDEX, 0 );
for( i = 0; i < 256; ++i )
WRITE_IB_REG( RADEON_PALETTE_DATA, (i << 16) | (i << 8) | i );
SUBMIT_IB();
}
static void setPalette( accelerator_info *ai, physical_head *head,
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;
(void)flags;
SHOW_FLOW( 3, "first=%d, count=%d", first, count );
if( vc->mode.space != B_CMAP8 ) {
SHOW_ERROR0( 2, "Tried to set palette in non-palette mode" );
return;
}
setPalette( ai, &si->heads[vc->heads[0].physical_head], count, first, color_data );
if( vc->independant_heads > 1 )
setPalette( ai, &si->heads[vc->heads[1].physical_head], count, first, color_data );
}
// set palette of one DAC
static void setPalette( accelerator_info *ai, physical_head *head,
uint count, uint8 first, uint8 *color_data )
{
uint i;
START_IB();
selectPalette( head );
WRITE_IB_REG( RADEON_PALETTE_INDEX, first );
for( i = 0; i < count; ++i, color_data += 3 )
WRITE_IB_REG( RADEON_PALETTE_DATA,
((uint32)color_data[0] << 16) |
((uint32)color_data[1] << 8) |
color_data[2] );
SUBMIT_IB();
}
+415 -112
View File
@@ -1,59 +1,22 @@
/*
Copyright (c) 2002, Thomas Kurschel
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
Takes of PLL
Takes care of PLL
*/
#include "radeon_accelerant.h"
#include "pll_regs.h"
#include "pll_access.h"
#include "utils.h"
#include <stdlib.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 )
static void Radeon_PLLWaitForReadUpdateComplete( accelerator_info *ai, physical_head *head )
{
int i;
@@ -61,107 +24,437 @@ static void Radeon_PLLWaitForReadUpdateComplete( accelerator_info *ai, virtual_p
// 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 )
if( (Radeon_INPLL( ai->regs, ai->si->asic, head->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 )
static void Radeon_PLLWriteUpdate( accelerator_info *ai, physical_head *head )
{
Radeon_PLLWaitForReadUpdateComplete( ai, port );
Radeon_PLLWaitForReadUpdateComplete( ai, head );
Radeon_OUTPLLP( ai, port->is_crtc2 ? RADEON_P2PLL_REF_DIV : RADEON_PPLL_REF_DIV,
Radeon_OUTPLLP( ai->regs, ai->si->asic,
head->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 )
// calculate PLL dividers
// pll - info about PLL
// freq - whished frequency in Hz
// fixed_post_div - if != 0, fixed divider to be used
// dividers - filled with proper dividers
void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_div, pll_dividers *dividers )
{
vuint8 *regs = ai->regs;
uint32 save, tmp;
if( ai->si->asic != rt_r300 )
return;
// the PLL gets the reference
// pll_in = ref_freq / ref_div
// this must be within pll_in_min..pll_in_max
// the VCO of the PLL has the frequency
// vco = pll_in * feedback_div * extra_feedback_div
// = ref_freq / ref_div * feedback_div * extra_feedback_div
// where pre_feedback_div is hard-wired
// this must be within vco_min..vco_max
// the pixel clock is calculated as
// pll_out = vco / post_div / extra_post_div
// = ref_freq * feedback_div * extra_feedback_div / (ref_div * post_div * extra_post_div)
// where extra_post_div _may_ be choosable between 1 and 2
// synonyms are:
// ref_div = M
// feedback_div = N
// post_div = P
int
min_post_div_idx, max_post_div_idx,
post_div_idx, extra_post_div_idx,
best_post_div_idx, best_extra_post_div_idx;
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 );
uint32
best_ref_div, best_feedback_div,
best_freq, best_error, best_vco_dev;
best_error = 999999999;
// make compiler happy
best_post_div_idx = 0;
best_extra_post_div_idx = 0;
best_ref_div = 1;
best_feedback_div = 1;
best_freq = 1;
best_vco_dev = 1;
if( fixed_post_div == 0 ) {
min_post_div_idx = 0;
for(
max_post_div_idx = 0;
pll->post_divs[max_post_div_idx].divider != 0;
++max_post_div_idx )
;
--max_post_div_idx;
} else {
for(
min_post_div_idx = 0;
pll->post_divs[min_post_div_idx].divider != fixed_post_div;
++min_post_div_idx )
;
max_post_div_idx = min_post_div_idx;
//SHOW_FLOW( 2, "idx of fixed post divider: %d", min_post_div_idx );
}
// post dividers are quite restrictive, so they provide little search space only
for( extra_post_div_idx = 0; pll->extra_post_divs[extra_post_div_idx].divider != 0; ++extra_post_div_idx ) {
for( post_div_idx = min_post_div_idx; post_div_idx <= max_post_div_idx; ++post_div_idx ) {
uint32 ref_div;
uint32 post_div =
pll->post_divs[post_div_idx].divider
* pll->extra_post_divs[extra_post_div_idx].divider;
// post devider determines VCO frequency, so determine and verify it;
// freq is in Hz, everything else is in 10 kHz units
// we use 10 kHz units as long as possible to avoid uint32 overflows
uint32 vco = (freq / 10000) * post_div;
//SHOW_FLOW( 2, "post_div=%d, vco=%d", post_div, vco );
if( vco < pll->vco_min || vco > pll->vco_max )
continue;
//SHOW_FLOW0( 2, "jau" );
// we can either iterate through feedback or reference dividers;
// usually, there are fewer possible reference dividers, so I picked them
for( ref_div = pll->min_ref_div; ref_div <= pll->max_ref_div; ++ref_div ) {
uint32 feedback_div, cur_freq, error, vco_dev;
// this implies the frequency of the lock unit
uint32 pll_in = pll->ref_freq / ref_div;
if( pll_in < pll->pll_in_min || pll_in > pll->pll_in_max )
continue;
// well, only one variable is left
// timing is almost certainly valid, time to use Hz units
feedback_div = RoundDiv64(
(int64)freq * ref_div * post_div,
pll->ref_freq * 10000 * pll->extra_feedback_div);
if( feedback_div < pll->min_feedback_div ||
feedback_div > pll->max_feedback_div )
continue;
// let's see what we've got
cur_freq = RoundDiv64(
(int64)pll->ref_freq * 10000 * feedback_div * pll->extra_feedback_div,
ref_div * post_div );
// absolute error in terms of output clock
error = abs( cur_freq - freq );
// deviation from perfect VCO clock
vco_dev = abs( vco - pll->best_vco );
// if there is no optimal VCO frequency, choose setting with less error;
// if there is an optimal VCO frequency, choose new settings if
// - error is reduced significantly (100 Hz or more), or
// - output frequency is almost the same (less then 100 Hz difference) but
// VCO frequency is closer to best frequency
if( (pll->best_vco == 0 && error < best_error) ||
(pll->best_vco != 0 &&
(error < best_error - 100 ||
(abs( error - best_error ) < 100 && vco_dev < best_vco_dev ))))
{
best_post_div_idx = post_div_idx;
best_extra_post_div_idx = extra_post_div_idx;
best_ref_div = ref_div;
best_feedback_div = feedback_div;
best_freq = cur_freq;
best_error = error;
best_vco_dev = vco_dev;
}
}
}
}
dividers->post_code = pll->post_divs[best_post_div_idx].code;
dividers->post = pll->post_divs[best_post_div_idx].divider;
dividers->extra_post_code = pll->post_divs[best_extra_post_div_idx].code;
dividers->extra_post = pll->post_divs[best_extra_post_div_idx].divider;
dividers->ref = best_ref_div;
dividers->feedback = best_feedback_div;
dividers->freq = best_freq;
}
// with a TV timing given, find a corresponding CRT timing.
// both timing must meet at the end of a frame, but as the PLL has a
// limited frequency granularity, you don't really get a CRT timing
// with precisely the same frame rate; the solution is to tweak the CRT
// image a bit by making it wider/taller/smaller until the frame rate
// drift is under a given threshold;
// we follows two aims:
// - primary, keep frame rate in sync
// - secondary, only tweak as much as unavoidable
void Radeon_MatchCRTPLL(
const pll_info *pll,
uint32 tv_v_total, uint32 tv_h_total, uint32 tv_frame_size_adjust, uint32 freq,
const display_mode *mode, uint32 max_v_tweak, uint32 max_h_tweak,
uint32 max_frame_rate_drift, uint32 fixed_post_div,
pll_dividers *dividers,
display_mode *tweaked_mode )
{
uint32 v_tweak;
int32 v_tweak_dir;
uint32 pix_per_tv_frame;
SHOW_FLOW( 2, "fixed post divider: %d", fixed_post_div );
// number of TV pixels per frame
pix_per_tv_frame = tv_v_total * tv_h_total + tv_frame_size_adjust;
// starting with original data we tweak total horizontal and vertical size
// more and more until we find a proper CRT clock frequency
for( v_tweak = 0; v_tweak <= max_v_tweak; ++v_tweak ) {
for( v_tweak_dir = -1; v_tweak_dir <= 1; v_tweak_dir += 2 ) {
uint32 h_tweak;
int32 h_tweak_dir;
uint32 v_total = mode->timing.v_total + v_tweak * v_tweak_dir;
for( h_tweak = 0; h_tweak <= max_h_tweak; ++h_tweak ) {
for( h_tweak_dir = -1; h_tweak_dir <= 1; h_tweak_dir += 2 ) {
uint32 pix_per_crt_frame, frame_rate_drift;
uint32 crt_freq;
uint32 abs_crt_error;
uint32 h_total = mode->timing.h_total + h_tweak * h_tweak_dir;
// number of CRT pixels per frame
pix_per_crt_frame = v_total * h_total;
// frame rate must be:
// frame_rate = freq / pix_per_tv_half_frame
// because of interlace, we must use half frames
// pix_per_tv_half_frame = pix_per_tv_frame / 2
// to get a CRT image with the same frame rate, we get
// crt_freq = frame_rate * pix_per_crt_frame
// = freq / (pix_per_tv_frame / 2) * pix_per_crt_frame
// formula is reordered as usual to improve accuracy
crt_freq = (uint64)freq * pix_per_crt_frame * 2 / pix_per_tv_frame;
Radeon_CalcPLLDividers( pll, crt_freq, fixed_post_div, dividers );
// get absolute CRT clock error per second
abs_crt_error = abs( dividers->freq - crt_freq );
//SHOW_INFO( 2, "whished=%d, is=%d", crt_freq, dividers->freq );
// convert it to relative CRT clock error:
// rel_error = abs_crt_error / crt_freq
// now to absolute TV clock error per second:
// abs_tv_error = rel_error * tv_freq
// and finally to TV clock error per frame:
// frame_rate_drift = abs_tv_error / frame_rate
// = abs_crt_error / crt_freq * tv_freq / frame_rate
// this can be simplified by using:
// tv_freq = pix_per_tv_frame * frame_rate
// so we get:
// frame_rate_drift = abs_crt_error / crt_freq * pix_per_tv_frame * frame_rate / frame_rate
// = abs_crt_error / crt_freq * pix_per_tv_frame
frame_rate_drift = (uint64)abs_crt_error * pix_per_tv_frame / freq;
// if drift is within threshold, we take this setting and stop
// searching (later iteration will increasingly tweak screen size,
// and we don't really want that)
if( frame_rate_drift < max_frame_rate_drift ) {
SHOW_INFO( 2, "frame_rate_drift=%d, crt_freq=%d, v_total=%d, h_total=%d",
frame_rate_drift, crt_freq, v_total, h_total );
tweaked_mode->timing.pixel_clock = crt_freq;
tweaked_mode->timing.v_total = v_total;
tweaked_mode->timing.h_total = h_total;
return;
}
}
}
}
}
}
// table to map divider to register value
typedef struct {
int divider;
int bitvalue;
} post_div_entry;
static post_div_entry post_divs[] = {
static pll_divider_map post_divs[] = {
{ 1, 0 },
{ 2, 1 },
{ 4, 2 },
{ 8, 3 },
{ 3, 4 },
{ 16, 5 },
// { 16, 5 }, // at least for pll2 of M6, this value is reserved
{ 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 )
// normal PLLs have no extra post divider
static pll_divider_map extra_post_divs[] = {
{ 1, 1 },
{ 0, 0 }
};
// extra post-divider provided by Rage Theatre
static pll_divider_map external_extra_post_divs[] = {
{ 1, 0 },
{ 2, 1 },
{ 0, 0 }
};
// post-dividers of Rage Theatre
static pll_divider_map tv_post_divs[] = {
{ 1, 1 },
{ 2, 2 },
{ 3, 3 },
{ 4, 4 },
{ 5, 5 },
{ 6, 6 },
{ 7, 7 },
{ 8, 8 },
{ 9, 9 },
{ 10, 10 },
{ 11, 11 },
{ 12, 12 },
{ 13, 13 },
{ 14, 14 },
{ 15, 15 },
{ 0, 0 }
};
// get PLL parameters of TV PLL
void Radeon_GetTVPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_encoder )
{
post_div_entry *post_div;
SHOW_FLOW( 2, "freq=%ld", freq );
pll->post_divs = tv_post_divs;
pll->extra_post_divs = internal_encoder ? extra_post_divs : external_extra_post_divs;
pll->ref_freq = general_pll->ref_freq;
pll->vco_min = 10000;
pll->vco_max = 25000;
// I'm not sure about the upper limit
pll->min_ref_div = 4;
pll->max_ref_div = 0x3ff;
// in the original code, they set it to 330kHz if PAL is requested and
// quartz is 27 MHz, but I don't see how these circumstances can effect the
// mimimal PLL input frequency
pll->pll_in_min = 40;
// in the original code, they don't define an upper limit
pll->pll_in_max = 100;
pll->extra_feedback_div = 1;
pll->min_feedback_div = 4;
pll->max_feedback_div = 0x7ff;
pll->best_vco = 21000;
}
// 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;
// get PLL parameters of CRT PLL used in conjunction with TV-out
void Radeon_GetTVCRTPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_tv_encoder )
{
pll->post_divs = post_divs;
pll->extra_post_divs = extra_post_divs;
pll->ref_freq = general_pll->ref_freq;
// in sample code, these limits are set in a strange way;
// as a first shot, I use the BIOS provided limits
/*pll->vco_min = general_pll->min_pll_freq;
pll->vco_max = general_pll->max_pll_freq;*/
// in sample code, they use a variable post divider during calculation, but
// use a fixed post divider for programming - the variable post divider is
// multiplied to the feedback divider;
// because of the fixed post divider (3), the VCO always runs far out of
// its stable frequency range, so we have hack the limits
pll->vco_min = 4000;
pll->vco_max = general_pll->max_pll_freq;
// in sample code, lower limit is 4, but in register spec they say everything but 0/1
pll->min_ref_div = 2;
pll->max_ref_div = 0x3ff;
pll->pll_in_min = 20;
pll->pll_in_max = 100;
pll->extra_feedback_div = 1;
pll->min_feedback_div = 4;
pll->max_feedback_div = 0x7ff;
pll->best_vco = internal_tv_encoder ? 17500 : 21000;
}
// calculate PLL registers
// mode->timing.pixel_clock must be in Hz because required accuracy in TV-Out mode
// (old: freq is in 10kHz)
// fixed_dividers - if non-NULL, you can force a pre-calculated divider (used for TV-Out)
void Radeon_CalcPLLRegisters( general_pll_info *general_pll,
const display_mode *mode, pll_dividers *fixed_dividers, port_regs *values )
{
pll_dividers dividers;
if( fixed_dividers == NULL ) {
pll_info pll;
if( values->pll_output_freq >= pll->min_pll_freq
&& values->pll_output_freq <= pll->max_pll_freq )
break;
pll.post_divs = post_divs;
pll.extra_post_divs = extra_post_divs;
pll.ref_freq = general_pll->ref_freq;
pll.vco_min = general_pll->min_pll_freq;
pll.vco_max = general_pll->max_pll_freq;
pll.min_ref_div = 2;
pll.max_ref_div = 0x3ff;
pll.pll_in_min = 40;
pll.pll_in_max = 100;
pll.extra_feedback_div = 1;
pll.min_feedback_div = 4;
pll.max_feedback_div = 0x7ff;
pll.best_vco = 0;
SHOW_FLOW( 2, "freq=%ld", mode->timing.pixel_clock/*freq * 10000*/ );
Radeon_CalcPLLDividers( &pll, mode->timing.pixel_clock /*freq * 10000*/, 0, &dividers );
} else {
// dividers are precalculated, so use them
dividers = *fixed_dividers;
}
values->dot_clock_freq = dividers.freq;
values->feedback_div = dividers.feedback;
values->post_div = dividers.post;
values->pll_output_freq = dividers.freq * dividers.post;
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;
values->ppll_ref_div = dividers.ref;
values->ppll_div_3 = (dividers.feedback | (dividers.post_code << 16));
// this is mad: the PLL controls the horizontal length in sub-byte precision!
values->htotal_cntl = mode->timing.h_total & 7;
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 );
values->ppll_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 )
void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *values )
{
vuint8 *regs = ai->regs;
radeon_type asic = ai->si->asic;
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_OUTPLLP( regs, asic, head->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_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_CNTL : RADEON_PPLL_CNTL,
RADEON_PPLL_RESET
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN,
@@ -174,31 +467,40 @@ void Radeon_ProgramPLL( accelerator_info *ai, virtual_port *port, port_regs *val
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 );
if( ai->si->asic >= rt_r300 && !head->is_crtc2 ) {
// with r300, the reference divider of the first PLL was moved
// to another bit position; at the old location, you only find
// the "BIOS suggested divider"; no clue why they did that
Radeon_OUTPLLP( regs, asic,
RADEON_PPLL_REF_DIV,
values->ppll_ref_div << RADEON_PPLL_REF_DIV_ACC_SHIFT,
~RADEON_PPLL_REF_DIV_ACC_MASK );
} else {
Radeon_OUTPLLP( regs, asic,
head->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,
Radeon_OUTPLLP( regs, asic,
head->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,
Radeon_OUTPLLP( regs, asic,
head->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_PLLWriteUpdate( ai, head );
Radeon_PLLWaitForReadUpdateComplete( ai, head );
Radeon_OUTPLL( ai,
port->is_crtc2 ? RADEON_HTOTAL2_CNTL : RADEON_HTOTAL_CNTL,
Radeon_OUTPLL( regs, asic,
head->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_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_P2PLL_CNTL : RADEON_PPLL_CNTL, 0,
~(RADEON_PPLL_RESET
| RADEON_PPLL_SLEEP
| RADEON_PPLL_ATOMIC_UPDATE_EN
@@ -208,6 +510,7 @@ void Radeon_ProgramPLL( accelerator_info *ai, virtual_port *port, port_regs *val
snooze( 5000 );
// use PLL for pixel clock again
Radeon_OUTPLLP( ai, port->is_crtc2 ? RADEON_PIXCLKS_CNTL : RADEON_VCLK_ECP_CNTL,
Radeon_OUTPLLP( regs, asic,
head->is_crtc2 ? RADEON_PIXCLKS_CNTL : RADEON_VCLK_ECP_CNTL,
RADEON_VCLK_SRC_PPLL_CLK, ~RADEON_VCLK_SRC_SEL_MASK );
}
@@ -27,36 +27,62 @@ extern int debug_level_flow;
extern int debug_level_info;
extern int debug_level_error;
/*#define DEBUG_WAIT_ON_MSG 1000000
#define DEBUG_WAIT_ON_ERROR 1000000*/
#define DEBUG_MSG_PREFIX "Radeon - "
//#define DEBUG_MAX_LEVEL_FLOW 2
#define DEBUG_MAX_LEVEL_FLOW 2
#include "debug_ext.h"
// info about this accelerant
typedef struct accelerator_info {
virtual_card *vc;
virtual_card *vc; // associated virtual card
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;
area_id shared_info_area; // info shared between accelerants
area_id regs_area; // MM I/O registers
area_id virtual_card_area; // info about virtual card
// mapped-in (non)-local memory;
// as si->local_mem contains a pointer to the local frame buffer,
// only mt_pci and mt_agp are filled directly, mt_nonlocal contains
// a copy of either mt_pci or mt_agp, mt_local a copy of si->local_mem
struct {
area_id area; // area of clone
char *data; // CPU address of area
} mapped_memory[mt_last+1];
int accelerant_is_clone; // true, if this is a cloned accelerant
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;
display_mode *mode_list; // list of standard display modes
shared_info *si; // info shared between accelerants
} accelerator_info;
// SetDisplayMode.c
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 );
status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start );
// crtc.c
void Radeon_ReadCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values );
uint16 Radeon_GetHSyncFudge( physical_head *head, int datatype );
void Radeon_CalcCRTCRegisters( accelerator_info *ai, physical_head *head,
display_mode *mode, port_regs *values );
void Radeon_ProgramCRTCRegisters( accelerator_info *ai, physical_head *head,
port_regs *values );
// multimon.c
void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode );
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 );
@@ -64,47 +90,111 @@ 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 );
// ProposeDisplayMode.c
bool Radeon_GetFormat( int space, int *format, int *bpp );
status_t Radeon_CreateModeList( shared_info *si );
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 );
// pll.c
void Radeon_CalcPLLRegisters( general_pll_info *pll, const display_mode *mode, pll_dividers *fixed_dividers, port_regs *values );
void Radeon_ProgramPLL( accelerator_info *ai, physical_head *head, port_regs *values );
void Radeon_CalcPLLDividers( const pll_info *pll, uint32 freq, uint fixed_post_div, pll_dividers *dividers );
void Radeon_MatchCRTPLL(
const pll_info *pll,
uint32 tv_v_total, uint32 tv_h_total, uint32 tv_frame_size_adjust, uint32 freq,
const display_mode *mode, uint32 max_v_tweak, uint32 max_h_tweak,
uint32 max_frame_rate_drift, uint32 fixed_post_div,
pll_dividers *dividers,
display_mode *tweaked_mode );
void Radeon_GetTVPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_encoder );
void Radeon_GetTVCRTPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,
bool internal_tv_encoder );
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 );
// flat_panel.c
void Radeon_ReadRMXRegisters( accelerator_info *ai, port_regs *values );
void Radeon_CalcRMXRegisters( fp_info *flatpanel, display_mode *mode, bool use_rmx, port_regs *values );
void Radeon_ProgramRMXRegisters( accelerator_info *ai, port_regs *values );
void Radeon_SetCursorColors( accelerator_info *ai, virtual_port *port );
void Radeon_ReadFPRegisters( accelerator_info *ai, port_regs *values );
void Radeon_CalcFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values );
void Radeon_ProgramFPRegisters( accelerator_info *ai, physical_head *head,
fp_info *fp_port, port_regs *values );
void Radeon_Init2D( accelerator_info *ai, uint32 datatype );
int Radeon_WaitForIdle( accelerator_info *ai );
// dpms.c
status_t Radeon_SetDPMS( accelerator_info *ai, physical_head *head, int mode );
uint32 Radeon_GetDPMS( accelerator_info *ai, physical_head *head );
// Cursor.c
void Radeon_SetCursorColors( accelerator_info *ai, physical_head *head );
// Acceleration.c
void Radeon_Init2D( accelerator_info *ai );
void Radeon_AllocateVirtualCardStateBuffer( accelerator_info *ai );
void Radeon_FreeVirtualCardStateBuffer( accelerator_info *ai );
void Radeon_FillStateBuffer( accelerator_info *ai, uint32 datatype );
// driver_wrapper.c
status_t Radeon_WaitForIdle( accelerator_info *ai, bool keep_lock );
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 );
status_t Radeon_VIPRead( accelerator_info *ai, uint channel, uint address, uint32 *data );
status_t Radeon_VIPWrite( accelerator_info *ai, uint8 channel, uint address, uint32 data );
int Radeon_FindVIPDevice( accelerator_info *ai, uint32 device_id );
void Radeon_ActivateVirtualCard( accelerator_info *ai );
// settings.cpp
void Radeon_ReadSettings( virtual_card *vc );
void Radeon_WriteSettings( virtual_card *vc );
// overlay.c
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 );
// EngineManagement.c
void Radeon_Spin( uint32 delay );
// monitor_detection.c
void Radeon_DetectDisplays( accelerator_info *ai );
// tv_out.c
void Radeon_DetectTVOut( accelerator_info *ai );
void Radeon_CalcTVParams( const general_pll_info *general_pll, tv_params *params,
const tv_timing *tv_timing, bool internal_encoder,
const display_mode *mode, display_mode *tweaked_mode );
void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing *timing,
tv_params *params, port_regs *values, physical_head *head,
bool internal_encoder, tv_standard tv_format );
void Radeon_ProgramTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder );
void Radeon_ReadTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder );
extern tv_timing Radeon_std_tv_timing[6];
// palette.c
void Radeon_InitPalette( accelerator_info *ai, physical_head *head );
// monitor_routing.h
void Radeon_ReadMonitorRoutingRegs( accelerator_info *ai, physical_head *head,
port_regs *values );
void Radeon_CalcMonitorRouting( accelerator_info *ai, physical_head *head,
port_regs *values );
void Radeon_ProgramMonitorRouting( accelerator_info *ai, physical_head *head, port_regs *values );
void Radeon_SetupDefaultMonitorRouting( accelerator_info *ai, int whished_num_heads );
#ifdef __cplusplus
}
@@ -1,73 +0,0 @@
/*
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;
}
+4 -14
View File
@@ -21,22 +21,19 @@
#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;
vc->swap_displays = false;
// per default, show overlay on first port
//vc->whished_overlay_port = 0;
@@ -59,8 +56,8 @@ void Radeon_ReadSettings( virtual_card *vc )
if( settings.Unflatten( &file ) != B_OK )
return;
if( settings.FindBool( "SwapDisplays", &vc->swapDisplays ) != B_OK )
vc->swapDisplays = false;
if( settings.FindBool( "SwapDisplays", &vc->swap_displays ) != B_OK )
vc->swap_displays = false;
if( settings.FindInt32( "MultiMonitorMode", &tmp ) != B_OK )
tmp = mm_combine;
@@ -80,16 +77,10 @@ void Radeon_ReadSettings( virtual_card *vc )
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;
@@ -108,12 +99,11 @@ void Radeon_WriteSettings( virtual_card *vc )
BMessage settings;
settings.AddBool( "SwapDisplays", vc->swapDisplays );
settings.AddBool( "SwapDisplays", vc->swap_displays );
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
@@ -1,127 +0,0 @@
/*
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;
}
+779
View File
@@ -0,0 +1,779 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon accelerant
Programming of TV-out unit, both internal and Rage Theatre
*/
#include "radeon_interface.h"
#include "radeon_accelerant.h"
#include "pll_regs.h"
#include "theatre_regs.h"
#include "tv_out_regs.h"
#include "pll_access.h"
#include "utils.h"
#include "stddef.h"
// fixed-point resolution of UV scaler increment
#define TV_UV_INC_FIX_SHIFT 14
#define TV_UV_INC_FIX_SCALE (1 << TV_UV_INC_FIX_SHIFT)
// fixed point resolution of UV scaler initialization
#define TV_UV_INIT_FIX_SHIFT 6
// calculate time when TV timing must be restarted
static void Radeon_CalcTVRestart( tv_params *params, const display_mode *mode,
uint16 h_blank, uint16 f_total )
{
uint32 h_first, v_first = 0, f_first;
uint32 tmp_uv_accum_sum;
uint16 uv_accum_frac, uv_accum_int;
uint line;
uint32 how_early = 0;
int32 first_num, restart_to_first_active_pixel_to_FIFO;
uint32 time_to_active;
// this is all black magic - you are not supposed to understand this
h_first = 9;
f_first = 0;
tmp_uv_accum_sum = params->uv_accum_init << (TV_UV_INC_FIX_SHIFT - TV_UV_INIT_FIX_SHIFT);
uv_accum_frac = tmp_uv_accum_sum & (TV_UV_INC_FIX_SCALE - 1);
uv_accum_int = (tmp_uv_accum_sum >> TV_UV_INC_FIX_SHIFT) & 7;
// at line disp + 18 the accumulator is initialized;
// simulate timing during vertical blank and find the last CRT line where
// a new TV line is started
// (actually, I think this calculation is wrong)
for( line = mode->timing.v_display - 1 + 18; line < mode->timing.v_total; ++line ) {
if( uv_accum_int > 0 ) {
--uv_accum_int;
} else {
v_first = line + 1;
how_early = uv_accum_frac * mode->timing.h_total;
uv_accum_int = ((uv_accum_frac + params->uv_inc) >> TV_UV_INC_FIX_SHIFT) - 1;
uv_accum_frac = (uv_accum_frac + params->uv_inc) & (TV_UV_INC_FIX_SCALE - 1);
}
}
//SHOW_FLOW( 2, "f_first=%d, v_first=%d, h_first=%d", f_first, v_first, h_first );
// theoretical time when restart should be started
first_num =
f_first * mode->timing.v_total * mode->timing.h_total
+ v_first * mode->timing.h_total
+ h_first;
first_num += (how_early + TV_UV_INC_FIX_SCALE / 2) >> TV_UV_INC_FIX_SHIFT;
// TV logic needs extra clocks to restart
time_to_active = params->tv_clocks_to_active + 3;
// get delay until first bytes can be read from FIFO
restart_to_first_active_pixel_to_FIFO =
(int)(
(int64)time_to_active * params->crt_dividers.freq / params->tv_dividers.freq
- (int64)(h_blank * params->crt_dividers.freq / params->tv_dividers.freq) / 2)
- mode->timing.h_display / 2
+ mode->timing.h_total / 2;
// do restart a bit early to compensate delays
first_num -= restart_to_first_active_pixel_to_FIFO;
SHOW_FLOW( 2, "restart_to_first_active_pixel_to_FIFO=%d", restart_to_first_active_pixel_to_FIFO );
// make restart time positive
// ("%" operator doesn't like negative numbers)
first_num += f_total * mode->timing.v_total * mode->timing.h_total;
//SHOW_FLOW( 2, "first_num=%d", first_num );
// convert clocks to screen position
params->f_restart = (first_num / (mode->timing.v_total * mode->timing.h_total)) % f_total;
first_num %= mode->timing.v_total * mode->timing.h_total;
params->v_restart = (first_num / mode->timing.h_total) % mode->timing.v_total;
first_num %= mode->timing.v_total;
params->h_restart = first_num;
SHOW_FLOW( 2, "Restart in frame %d, line %d, pixel %d",
params->f_restart, params->v_restart, params->h_restart );
}
// thresholds for flicker fixer algorithm
static int8 y_flicker_removal[5] = { 6, 5, 4, 3, 2 };
// associated filter parameters scaled by 8(!)
static int8 y_saw_tooth_slope[5] = { 1, 2, 2, 4, 8 };
static int8 y_coeff_value[5] = { 2, 2, 0, 4, 0 };
// these values are not scaled
static bool y_coeff_enable[5] = { 1, 1, 0, 1, 0 };
#define countof( a ) (sizeof( (a) ) / sizeof( (a)[0] ))
// fixed point resolution of saw filter parameters
#define TV_SAW_FILTER_FIX_SHIFT 13
#define TV_SAW_FILTER_FIX_SCALE (1 << TV_SAW_FILTER_FIX_SHIFT)
// fixed point resolution of flat filter parameter
#define TV_Y_COEFF_FIX_SHIFT 8
#define TV_Y_COEFF_FIX_SCALE (1 << TV_Y_COEFF_FIX_SHIFT)
// calculate flicker fixer parameters
static void Radeon_CalcTVFlickerFixer( tv_params *params )
{
int8 flicker_removal;
uint i;
// first, we determine how much flickering should be removed
// I reckon that we could tweak it a bit hear as only
// uv_inc <= flicker_removal < uv_inc * 2
// must be assured
flicker_removal = (params->uv_inc + (TV_UV_INC_FIX_SCALE / 2)) >> TV_UV_INC_FIX_SHIFT;
for( i = 0; i < countof( y_flicker_removal ); ++i ) {
if( flicker_removal == y_flicker_removal[i] )
break;
}
// use most aggresive filtering if not in list
if( i > countof( y_flicker_removal ))
i = countof( y_flicker_removal ) - 1;
params->y_saw_tooth_slope = y_saw_tooth_slope[i] * (TV_SAW_FILTER_FIX_SCALE / 8);
params->y_saw_tooth_amp = ((uint32)params->y_saw_tooth_slope * params->uv_inc) >> TV_UV_INC_FIX_SHIFT;
params->y_fall_accum_init = ((uint32)params->y_saw_tooth_slope * params->uv_accum_init) >> TV_UV_INC_FIX_SHIFT;
if( flicker_removal - (params->uv_inc >> TV_UV_INC_FIX_SHIFT)
< (params->uv_accum_init >> TV_UV_INIT_FIX_SHIFT))
{
params->y_rise_accum_init =
(((flicker_removal << TV_UV_INIT_FIX_SHIFT) - params->uv_accum_init) *
params->y_saw_tooth_slope) >> TV_UV_INIT_FIX_SHIFT;
} else {
params->y_rise_accum_init =
(((flicker_removal << TV_UV_INIT_FIX_SHIFT) - params->uv_accum_init - params->y_accum_init) *
params->y_saw_tooth_slope) >> TV_UV_INIT_FIX_SHIFT;
}
params->y_coeff_enable = y_coeff_enable[i];
params->y_coeff_value = y_coeff_value[i] * TV_Y_COEFF_FIX_SCALE / 8;
}
// correct sync position after tweaking total size
static void Radeon_AdoptSync( const display_mode *mode, display_mode *tweaked_mode )
{
uint16
h_over_plus, h_sync_width, tweaked_h_over_plus,
v_over_plus, v_sync_width, tweaked_v_over_plus;
h_over_plus = mode->timing.h_sync_start - mode->timing.h_display;
h_sync_width = mode->timing.h_sync_end - mode->timing.h_sync_start;
// we want start of sync at same relative position of blank
tweaked_h_over_plus = (uint32)h_over_plus *
(tweaked_mode->timing.h_total - mode->timing.h_display - h_sync_width ) /
(mode->timing.h_total - mode->timing.h_display - h_sync_width);
tweaked_mode->timing.h_sync_start = mode->timing.h_display + tweaked_h_over_plus;
tweaked_mode->timing.h_sync_end = tweaked_mode->timing.h_sync_start + h_sync_width;
v_over_plus = mode->timing.v_sync_start - mode->timing.v_display;
v_sync_width = mode->timing.v_sync_end - mode->timing.v_sync_start;
tweaked_v_over_plus = (uint32)v_over_plus *
(tweaked_mode->timing.v_total - mode->timing.v_display - v_sync_width ) /
(mode->timing.v_total - mode->timing.v_display - v_sync_width);
// we really should verify whether the resulting mode is still valid;
// this is a start
tweaked_v_over_plus = min( 1, tweaked_v_over_plus );
tweaked_mode->timing.v_sync_start = mode->timing.v_display + tweaked_v_over_plus;
tweaked_mode->timing.v_sync_end = tweaked_mode->timing.v_sync_start + v_sync_width;
}
#define TV_VERT_LEAD_IN_LINES 2
// calculate TV parameters
void Radeon_CalcTVParams( const general_pll_info *general_pll, tv_params *params,
const tv_timing *tv_timing, bool internal_encoder,
const display_mode *mode, display_mode *tweaked_mode )
{
pll_info tv_pll, crt_pll;
uint16 start_line, lines_before_active;
SHOW_FLOW( 2, "internal_encoder=%s", internal_encoder ? "yes" : "no" );
params->mode888 = true;
Radeon_GetTVPLLConfiguration( general_pll, &tv_pll, internal_encoder );
Radeon_CalcPLLDividers( &tv_pll, tv_timing->freq, 0, &params->tv_dividers );
Radeon_GetTVCRTPLLConfiguration( general_pll, &crt_pll, internal_encoder );
// initially, we try to keep to requested mode
*tweaked_mode = *mode;
// tweak CRT mode if necessary to match TV frame timing
Radeon_MatchCRTPLL(
&crt_pll,
tv_timing->v_total, tv_timing->h_total, tv_timing->frame_size_adjust,
tv_timing->freq,
mode, 2, 40,
internal_encoder ? 6 : 0, 2 + params->mode888,
&params->crt_dividers, tweaked_mode );
// adopt synchronization to make tweaked mode look like original mode
Radeon_AdoptSync( mode, tweaked_mode );
// timing magic
start_line =
tv_timing->h_sync_len
+ tv_timing->h_setup_delay
+ tv_timing->h_active_delay
- tv_timing->h_genclk_delay;
lines_before_active =
(tv_timing->v_field_total - tv_timing->v_active_lines) / 2 - 1
- TV_VERT_LEAD_IN_LINES + 1;
params->tv_clocks_to_active = (uint32)lines_before_active * tv_timing->h_total + start_line;
// calculate scaling.
// this must be done CalcTVRestart() or TVFlickerFixer() is called
// start accumulator always with 0.25
params->uv_accum_init = 0x10;
// this value seems to be fixed (it's not written to any register but used
// at some calculations)
params->y_accum_init = 0;
// for scaling ratio, take care that v_field_total is for full, not for half frames,
// therefore we devide it v_field_total by 2
params->uv_inc = (tweaked_mode->timing.v_total << TV_UV_INC_FIX_SHIFT)
* 2 / tv_timing->v_field_total;
params->h_inc =
((int64)tweaked_mode->timing.h_display * 4096 /
(tv_timing->h_active_len + tv_timing->h_active_delay) << FIX_SHIFT) / tv_timing->scale;
Radeon_CalcTVRestart( params, tweaked_mode,
tv_timing->h_total - tv_timing->h_active_len, tv_timing->f_total );
Radeon_CalcTVFlickerFixer( params );
}
// timing of TV standards;
// the index is of type tv_standard
tv_timing Radeon_std_tv_timing[6] = {
{42954540, 2730, 200, 28, 200, 110, 2170, 525, 440, 525, 2, 1, 0, 0.88 * FIX_SCALE}, /* ntsc */
{53203425, 3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2, 3, -6, 0.91 * FIX_SCALE}, /* pal */
{42907338, 2727, 200, 28, 200, 110, 2170, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE}, /* palm */
{42984675, 2751, 202, 28, 202, 110, 2190, 625, 510, 625, 2, 3, 0, 0.91 * FIX_SCALE}, /* palnc */
{53203425, 3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2, 3, 0, 0.91 * FIX_SCALE}, /* scart pal ??? */
{53203425, 3405, 250, 28, 320, 80, 2627, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE}, /* pal 60 */
};
// compose TV register content
// as TV-Out uses a CRTC, it reprograms a PLL to create an unscaled image;
// as a result, you must not call Radeon_CalcPLLRegisters() afterwards
// TBD: what's special in terms of PLL in TV-Out mode?
void Radeon_CalcTVRegisters( accelerator_info *ai, display_mode *mode, tv_timing *timing,
tv_params *params, port_regs *values, physical_head *head,
bool internal_encoder, tv_standard tv_format )
{
// some register's content isn't created from scratch but
// only modified, so we need the original content first
Radeon_ReadTVRegisters( ai, values, internal_encoder );
values->tv_ftotal = timing->f_total;
values->tv_vscaler_cntl1 =
(values->tv_vscaler_cntl1 & 0xe3ff0000) |
params->uv_inc;
if( internal_encoder ) {
values->tv_vscaler_cntl1 |= RADEON_TV_VSCALER_CNTL1_RESTART_FIELD;
if( mode->timing.h_display == 1024 )
values->tv_vscaler_cntl1 |= 4 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT;
else
values->tv_vscaler_cntl1 |= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT;
} else {
values->tv_vscaler_cntl1 |= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT;
}
values->tv_y_saw_tooth_cntl =
params->y_saw_tooth_amp |
(params->y_saw_tooth_slope << RADEON_TV_Y_SAW_TOOTH_CNTL_SLOPE_SHIFT);
values->tv_y_fall_cntl =
params->y_fall_accum_init |
RADEON_TV_Y_FALL_CNTL_Y_FALL_PING_PONG |
(params->y_coeff_enable ? RADEON_TV_Y_FALL_CNTL_Y_COEFF_EN : 0) |
(params->y_coeff_value << RADEON_TV_Y_FALL_CNTL_Y_COEFF_VALUE_SHIFT);
values->tv_y_rise_cntl =
params->y_rise_accum_init |
RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG;
values->tv_vscaler_cntl2 =
(values->tv_vscaler_cntl2 & 0x00ffffff) |
RADEON_TV_VSCALER_CNTL2_DITHER_MODE |
RADEON_TV_VSCALER_CNTL2_Y_OUTPUT_DITHER_EN |
RADEON_TV_VSCALER_CNTL2_UV_OUTPUT_DITHER_EN |
RADEON_TV_VSCALER_CNTL2_UV_TO_BUF_DITHER_EN |
(params->uv_accum_init << RADEON_TV_VSCALER_CNTL2_UV_ACCUM_INIT_SHIFT);
values->tv_hrestart = params->h_restart;
values->tv_vrestart = params->v_restart;
values->tv_frestart = params->f_restart;
values->tv_tv_pll_cntl =
(params->tv_dividers.ref & RADEON_TV_PLL_CNTL_TV_M0_LO_MASK) |
((params->tv_dividers.feedback & RADEON_TV_PLL_CNTL_TV_N0_LO_MASK)
<< RADEON_TV_PLL_CNTL_TV_N0_LO_SHIFT) |
((params->tv_dividers.ref >> RADEON_TV_PLL_CNTL_TV_M0_LO_BITS)
<< RADEON_TV_PLL_CNTL_TV_M0_HI_SHIFT) |
((params->tv_dividers.feedback >> RADEON_TV_PLL_CNTL_TV_N0_LO_BITS)
<< RADEON_TV_PLL_CNTL_TV_N0_HI_SHIFT) |
RADEON_TV_PLL_CNTL_TV_SLIP_EN |
(params->tv_dividers.post << RADEON_TV_PLL_CNTL_TV_P_SHIFT) |
RADEON_TV_PLL_CNTL_TV_DTO_EN;
values->tv_crt_pll_cntl =
(params->crt_dividers.ref & RADEON_TV_CRT_PLL_CNTL_M0_LO_MASK) |
((params->crt_dividers.feedback & RADEON_TV_CRT_PLL_CNTL_N0_LO_MASK)
<< RADEON_TV_CRT_PLL_CNTL_N0_LO_SHIFT) |
((params->crt_dividers.ref >> RADEON_TV_CRT_PLL_CNTL_M0_LO_BITS)
<< RADEON_TV_CRT_PLL_CNTL_M0_HI_SHIFT) |
((params->crt_dividers.feedback >> RADEON_TV_CRT_PLL_CNTL_N0_LO_BITS)
<< RADEON_TV_CRT_PLL_CNTL_N0_HI_SHIFT) |
(params->crt_dividers.extra_post == 2 ? RADEON_TV_CRT_PLL_CNTL_CLKBY2 : 0);
values->tv_clock_sel_cntl =
(values->tv_clock_sel_cntl & ~0x3d) |
0x33 |
((params->crt_dividers.post_code - 1) << 2);
values->tv_clkout_cntl = 0x09;
if( !internal_encoder )
values->tv_clkout_cntl |= 1 << 5;
values->tv_htotal = mode->timing.h_total - 1;
values->tv_hsize = mode->timing.h_display;
values->tv_hdisp = mode->timing.h_display - 1;
values->tv_hstart =
internal_encoder ?
mode->timing.h_display - params->mode888 - 12 :
mode->timing.h_display - params->mode888 + 12;
values->tv_vtotal = mode->timing.v_total - 1;
values->tv_vdisp = mode->timing.v_display - 1;
values->tv_sync_size = mode->timing.h_display + 8;
values->tv_timing_cntl =
(values->tv_timing_cntl & 0xfffff000) |
params->h_inc;
if( ai->si->asic >= rt_r300 ) {
// this is a hack to fix improper UV scaling
// (at least this is what the sample code says)
values->tv_timing_cntl =
(values->tv_timing_cntl & 0x00ffffff) |
((0x72 * 640 / mode->timing.h_display)
<< RADEON_TV_TIMING_CNTL_UV_OUTPUT_POST_SCALE_SHIFT);
}
values->feedback_div = params->crt_dividers.feedback;
values->post_div = params->crt_dividers.post;
values->ppll_ref_div = params->crt_dividers.ref;
values->ppll_div_3 =
params->crt_dividers.feedback |
(params->crt_dividers.post_code << 16);
values->htotal_cntl = mode->timing.h_total & 7;
if( internal_encoder ) {
values->tv_dac_cntl =
// TBD: DAC is always set to NTSC mode, though there is a PAL mode!
values->tv_dac_cntl =
RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD |
RADEON_TV_DAC_CNTL_STD_NTSC/*RADEON_TV_DAC_CNTL_STD_PAL*/ |
(8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) |
(6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT);
} else {
values->tv_dac_cntl =
(values->tv_dac_cntl & ~(RADEON_TV_DAC_CNTL_STD_NTSC | 0x88 |
RADEON_TV_DAC_CNTL_BGSLEEP | RADEON_TV_DAC_CNTL_PEDESTAL)) |
RADEON_TV_DAC_CNTL_DETECT |
RADEON_TV_DAC_CNTL_NBLANK |
RADEON_TV_DAC_CNTL_NHOLD;
}
values->tv_modulator_cntl1 =
values->tv_modulator_cntl1 & ~(
RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN |
RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL |
RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK |
RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK);
switch( tv_format ) {
case ts_ntsc:
values->tv_dac_cntl |=
values->tv_modulator_cntl1 |=
RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL |
(0x46 << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) |
(0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT);
values->tv_modulator_cntl2 =
(-111 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) |
((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT);
break;
case ts_pal:
values->tv_modulator_cntl1 |=
RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN |
RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL |
(0x3b << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) |
(0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT);
values->tv_modulator_cntl2 =
(-78 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) |
((62 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT);
break;
case ts_scart_pal:
// from register spec
values->tv_modulator_cntl1 |=
RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN |
RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL;
values->tv_modulator_cntl2 =
(0 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) |
((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT);
break;
default:
// there are many formats missing, sigh...
}
values->tv_data_delay_a = 0x0b0c0a06;
values->tv_data_delay_b = 0x070a0a0c;
values->tv_frame_lock_cntl = internal_encoder ? 0 : 0xf;
if( internal_encoder ) {
values->tv_pll_cntl1 =
(4 << RADEON_TV_PLL_CNTL1_TVPCP_SHIFT) |
(4 << RADEON_TV_PLL_CNTL1_TVPVG_SHIFT) |
(2 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT) |
RADEON_TV_PLL_CNTL1_TVCLK_SRC_SEL_TVPLLCLK |
RADEON_TV_PLL_CNTL1_TVPLL_TEST;
values->tv_rgb_cntl =
((head->is_crtc2 ? 2 : 0) << RADEON_TV_RGB_CNTL_RGB_SRC_SEL_SHIFT) |
RADEON_TV_RGB_CNTL_RGB_DITHER_EN |
(0xb << RADEON_TV_RGB_CNTL_UVRAM_READ_MARGIN_SHIFT) |
(7 << RADEON_TV_RGB_CNTL_FIFORAM_FIFOMACRO_READ_MARGIN_SHIFT);
values->tv_pre_dac_mux_cntl =
RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN |
(0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);
} else {
// this register seems to have completely different meaning on Theatre chip
values->tv_pll_cntl1 =
(1 << 3) | (1 << 4) | (4 << 8) | (1 << 11)
| (5 << 13) | (4 << 16) | (1 << 19) | (5 << 21);
// this one too
values->tv_rgb_cntl = params->mode888;
values->tv_pre_dac_mux_cntl =
RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN |
RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN |
(0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);
}
values->tv_pll_fine_cntl = 0;
// TBD: this is certainly broken
// (they do an ((orig & 0xe0) & 0x600) which is constant zero)
values->tv_master_cntl = 0;
if( tv_format == ts_ntsc )
values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX;
else
values->tv_master_cntl &= ~RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX;
// this is missing in the sample code
values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_TV_ON;
SHOW_FLOW( 2, "tv_master_cntl=%x", values->tv_master_cntl );
values->tv_uv_adr = 0xc8;
}
// mapping of offset in port_regs to register address
typedef struct register_mapping {
uint16 address; // register address
uint16 offset; // offset in port_regs
} register_mapping;
// internal TV-encoder:
// registers to write before programming PLL
static const register_mapping intern_reg_mapping_before_pll[] = {
{ RADEON_TV_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) },
{ RADEON_TV_HRESTART, offsetof( port_regs, tv_hrestart ) },
{ RADEON_TV_VRESTART, offsetof( port_regs, tv_vrestart ) },
{ RADEON_TV_FRESTART, offsetof( port_regs, tv_frestart ) },
{ RADEON_TV_FTOTAL, offsetof( port_regs, tv_ftotal ) },
{ 0, 0 }
};
// PLL registers to program
static const register_mapping intern_reg_mapping_pll[] = {
{ RADEON_TV_PLL_CNTL, offsetof( port_regs, tv_tv_pll_cntl ) },
{ RADEON_TV_PLL_CNTL1, offsetof( port_regs, tv_pll_cntl1 ) },
{ RADEON_TV_PLL_FINE_CNTL, offsetof( port_regs, tv_pll_fine_cntl ) },
{ 0, 0 }
};
// registers to write after programming of PLL
static const register_mapping intern_reg_mapping_after_pll[] = {
{ RADEON_TV_HTOTAL, offsetof( port_regs, tv_htotal ) },
{ RADEON_TV_HDISP, offsetof( port_regs, tv_hdisp ) },
{ RADEON_TV_HSTART, offsetof( port_regs, tv_hstart ) },
{ RADEON_TV_VTOTAL, offsetof( port_regs, tv_vtotal ) },
{ RADEON_TV_VDISP, offsetof( port_regs, tv_vdisp ) },
{ RADEON_TV_TIMING_CNTL, offsetof( port_regs, tv_timing_cntl ) },
{ RADEON_TV_VSCALER_CNTL1, offsetof( port_regs, tv_vscaler_cntl1 ) },
{ RADEON_TV_VSCALER_CNTL2, offsetof( port_regs, tv_vscaler_cntl2 ) },
{ RADEON_TV_Y_SAW_TOOTH_CNTL, offsetof( port_regs, tv_y_saw_tooth_cntl ) },
{ RADEON_TV_Y_RISE_CNTL, offsetof( port_regs, tv_y_rise_cntl ) },
{ RADEON_TV_Y_FALL_CNTL, offsetof( port_regs, tv_y_fall_cntl ) },
{ RADEON_TV_MODULATOR_CNTL1, offsetof( port_regs, tv_modulator_cntl1 ) },
{ RADEON_TV_MODULATOR_CNTL2, offsetof( port_regs, tv_modulator_cntl2 ) },
{ RADEON_TV_RGB_CNTL, offsetof( port_regs, tv_rgb_cntl ) },
{ RADEON_TV_UV_ADR, offsetof( port_regs, tv_uv_adr ) },
{ RADEON_TV_PRE_DAC_MUX_CNTL, offsetof( port_regs, tv_pre_dac_mux_cntl ) },
{ 0, 0 }
};
// registers to write when things settled down
static const register_mapping intern_reg_mapping_finish[] = {
{ RADEON_TV_DAC_CNTL, offsetof( port_regs, tv_dac_cntl ) },
{ RADEON_TV_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) },
{ 0, 0 }
};
// Rage Theatre TV-Out:
// registers to write at first
static const register_mapping theatre_reg_mapping_start[] = {
{ THEATRE_VIP_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) },
{ THEATRE_VIP_TVO_DATA_DELAY_A, offsetof( port_regs, tv_data_delay_a ) },
{ THEATRE_VIP_TVO_DATA_DELAY_B, offsetof( port_regs, tv_data_delay_b ) },
{ THEATRE_VIP_CLKOUT_CNTL, offsetof( port_regs, tv_clkout_cntl ) },
{ THEATRE_VIP_PLL_CNTL0, offsetof( port_regs, tv_pll_cntl1 ) },
{ THEATRE_VIP_HRESTART, offsetof( port_regs, tv_hrestart ) },
{ THEATRE_VIP_VRESTART, offsetof( port_regs, tv_vrestart ) },
{ THEATRE_VIP_FRESTART, offsetof( port_regs, tv_frestart ) },
{ THEATRE_VIP_FTOTAL, offsetof( port_regs, tv_ftotal ) },
{ THEATRE_VIP_CLOCK_SEL_CNTL, offsetof( port_regs, tv_clock_sel_cntl ) },
{ THEATRE_VIP_TV_PLL_CNTL, offsetof( port_regs, tv_tv_pll_cntl ) },
{ THEATRE_VIP_CRT_PLL_CNTL, offsetof( port_regs, tv_crt_pll_cntl ) },
{ THEATRE_VIP_HTOTAL, offsetof( port_regs, tv_htotal ) },
{ THEATRE_VIP_HSIZE, offsetof( port_regs, tv_hsize ) },
{ THEATRE_VIP_HDISP, offsetof( port_regs, tv_hdisp ) },
{ THEATRE_VIP_HSTART, offsetof( port_regs, tv_hstart ) },
{ THEATRE_VIP_VTOTAL, offsetof( port_regs, tv_vtotal ) },
{ THEATRE_VIP_VDISP, offsetof( port_regs, tv_vdisp ) },
{ THEATRE_VIP_TIMING_CNTL, offsetof( port_regs, tv_timing_cntl ) },
{ THEATRE_VIP_VSCALER_CNTL, offsetof( port_regs, tv_vscaler_cntl1 ) },
{ THEATRE_VIP_VSCALER_CNTL2, offsetof( port_regs, tv_vscaler_cntl2 ) },
{ THEATRE_VIP_SYNC_SIZE, offsetof( port_regs, tv_sync_size ) },
{ THEATRE_VIP_Y_SAW_TOOTH_CNTL, offsetof( port_regs, tv_y_saw_tooth_cntl ) },
{ THEATRE_VIP_Y_RISE_CNTL, offsetof( port_regs, tv_y_rise_cntl ) },
{ THEATRE_VIP_Y_FALL_CNTL, offsetof( port_regs, tv_y_fall_cntl ) },
{ THEATRE_VIP_MODULATOR_CNTL1, offsetof( port_regs, tv_modulator_cntl1 ) },
{ THEATRE_VIP_MODULATOR_CNTL2, offsetof( port_regs, tv_modulator_cntl2 ) },
{ THEATRE_VIP_RGB_CNTL, offsetof( port_regs, tv_rgb_cntl ) },
{ THEATRE_VIP_UV_ADR, offsetof( port_regs, tv_uv_adr ) },
{ THEATRE_VIP_PRE_DAC_MUX_CNTL, offsetof( port_regs, tv_pre_dac_mux_cntl ) },
{ THEATRE_VIP_FRAME_LOCK_CNTL, offsetof( port_regs, tv_frame_lock_cntl ) },
{ 0, 0 }
};
// registers to write when things settled down
static const register_mapping theatre_reg_mapping_finish[] = {
{ THEATRE_VIP_TV_DAC_CNTL, offsetof( port_regs, tv_dac_cntl ) },
{ THEATRE_VIP_MASTER_CNTL, offsetof( port_regs, tv_master_cntl ) },
{ 0, 0 }
};
// write list of MM I/O registers
static void writeMMIORegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping )
{
vuint8 *regs = ai->regs;
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );
OUTREG( regs, mapping->address, *(uint32 *)((char *)(values) + mapping->offset) );
}
}
// write list of PLL registers
static void writePLLRegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );
Radeon_OUTPLL( ai->regs, ai->si->asic,
mapping->address, *(uint32 *)((char *)(values) + mapping->offset) );
}
}
// write list of Rage Theatre registers
static void writeTheatreRegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
Radeon_VIPWrite( ai, ai->si->theatre_channel, mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );
}
}
// program TV-Out registers
void Radeon_ProgramTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder )
{
uint32 orig_tv_master_cntl = values->tv_master_cntl;
// disable TV-out when registers are setup
// it gets enabled again when things have settled down
values->tv_master_cntl |=
RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
(uint32)0xf0;
if( internal_encoder ) {
writeMMIORegList( ai, values, intern_reg_mapping_before_pll );
writePLLRegList( ai, values, intern_reg_mapping_pll );
writeMMIORegList( ai, values, intern_reg_mapping_after_pll );
snooze( 50000 );
values->tv_master_cntl = orig_tv_master_cntl;
writeMMIORegList( ai, values, intern_reg_mapping_finish );
} else {
writeTheatreRegList( ai, values, theatre_reg_mapping_start );
snooze( 50000 );
values->tv_master_cntl = orig_tv_master_cntl;
writeTheatreRegList( ai, values, intern_reg_mapping_finish );
}
}
// read list of MM I/O registers
static void readMMIORegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping )
{
vuint8 *regs = ai->regs;
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
*(uint32 *)((char *)(values) + mapping->offset) =
INREG( regs, mapping->address );
/* SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
}
}
// read list of PLL registers
static void readPLLRegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
*(uint32 *)((char *)(values) + mapping->offset) =
Radeon_INPLL( ai->regs, ai->si->asic, mapping->address );
/* SHOW_FLOW( 2, "%x=%x", mapping->address,
*(uint32 *)((char *)(values) + mapping->offset) );*/
}
}
// read list of Rage Theatre registers
static void readTheatreRegList( accelerator_info *ai, port_regs *values, const register_mapping *mapping )
{
for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
Radeon_VIPRead( ai, ai->si->theatre_channel, mapping->address,
(uint32 *)((char *)(values) + mapping->offset) );
}
}
// read TV-Out registers
void Radeon_ReadTVRegisters( accelerator_info *ai, port_regs *values, bool internal_encoder )
{
if( internal_encoder ) {
readMMIORegList( ai, values, intern_reg_mapping_before_pll );
readPLLRegList( ai, values, intern_reg_mapping_pll );
readMMIORegList( ai, values, intern_reg_mapping_after_pll );
readMMIORegList( ai, values, intern_reg_mapping_finish );
} else {
readTheatreRegList( ai, values, theatre_reg_mapping_start );
readTheatreRegList( ai, values, intern_reg_mapping_finish );
}
}
// detect TV-Out encoder
void Radeon_DetectTVOut( accelerator_info *ai )
{
shared_info *si = ai->si;
SHOW_FLOW0( 0, "" );
switch( si->tv_chip ) {
case tc_external_rt1: {
// for external encoder, we need the VIP channel
int channel = Radeon_FindVIPDevice( ai, THEATRE_ID );
if( channel < 0 ) {
SHOW_ERROR0( 2, "This card needs a Rage Theatre for TV-Out, but there is none." );
si->tv_chip = tc_none;
} else {
SHOW_INFO( 2, "Rage Theatre found on VIP channel %d", channel );
si->theatre_channel = channel;
}
break; }
default:
// for internal encoder, we don't have to look farther - it must be there
}
}
-26
View File
@@ -1,26 +0,0 @@
/*
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
@@ -1,25 +0,0 @@
#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