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:
@@ -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 ;
|
||||
|
||||
@@ -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;
|
||||
+5
-2
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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] );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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, ÷rs );
|
||||
} 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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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, ¶ms->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,
|
||||
¶ms->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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user