From 2a37e4c1cf59b445e309a3880ceed82d25a0d107 Mon Sep 17 00:00:00 2001 From: shadow303 Date: Fri, 16 Jul 2004 00:48:12 +0000 Subject: [PATCH] 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 --- src/add-ons/accelerants/Jamfile | 1 + src/add-ons/accelerants/common/Jamfile | 12 + .../accelerants/{radeon => common}/ddc.c | 30 +- .../accelerants/{radeon => common}/ddc_int.h | 0 .../{radeon/edid.c => common/decode_edid.c} | 7 +- .../{radeon => common}/dump_edid.c | 0 .../accelerants/{radeon => common}/i2c.c | 16 +- src/add-ons/accelerants/radeon/Acceleration.c | 336 ++++---- src/add-ons/accelerants/radeon/CP.c | 581 +++++++------ src/add-ons/accelerants/radeon/CP.h | 119 +++ src/add-ons/accelerants/radeon/CPMicroCode.h | 786 ------------------ src/add-ons/accelerants/radeon/Cursor.c | 72 +- .../accelerants/radeon/EngineManagment.c | 65 +- .../accelerants/radeon/GetAccelerantHook.c | 2 + src/add-ons/accelerants/radeon/GetModeInfo.c | 9 +- src/add-ons/accelerants/radeon/GlobalData.h | 2 + .../accelerants/radeon/InitAccelerant.c | 91 +- src/add-ons/accelerants/radeon/Jamfile | 18 +- .../accelerants/radeon/ProposeDisplayMode.c | 88 +- .../accelerants/radeon/SetDisplayMode.c | 328 +++----- src/add-ons/accelerants/radeon/crtc.c | 144 ++-- src/add-ons/accelerants/radeon/ddc.h | 21 - src/add-ons/accelerants/radeon/dpms.c | 221 +++-- .../accelerants/radeon/driver_wrapper.c | 78 ++ src/add-ons/accelerants/radeon/edid.h | 146 ---- src/add-ons/accelerants/radeon/edid_raw.h | 278 ------- src/add-ons/accelerants/radeon/engine_sync.c | 247 ------ src/add-ons/accelerants/radeon/flat_panel.c | 335 ++++---- src/add-ons/accelerants/radeon/i2c.h | 69 -- src/add-ons/accelerants/radeon/log_coll.c | 129 --- src/add-ons/accelerants/radeon/log_coll.h | 76 -- src/add-ons/accelerants/radeon/log_dump.c | 75 -- src/add-ons/accelerants/radeon/log_dump.h | 17 - src/add-ons/accelerants/radeon/log_enum.h | 18 - src/add-ons/accelerants/radeon/log_names.h | 18 - .../accelerants/radeon/monitor_detection.c | 687 +++++++++++++++ .../accelerants/radeon/monitor_routing.c | 301 +++++++ src/add-ons/accelerants/radeon/multimon.c | 45 +- src/add-ons/accelerants/radeon/overlay.c | 296 ++++--- .../accelerants/radeon/overlay_management.c | 47 +- src/add-ons/accelerants/radeon/palette.c | 88 ++ src/add-ons/accelerants/radeon/pll.c | 527 +++++++++--- .../accelerants/radeon/radeon_accelerant.h | 164 +++- .../accelerants/radeon/radeonlog_dump.c | 73 -- src/add-ons/accelerants/radeon/settings.cpp | 18 +- src/add-ons/accelerants/radeon/test_ddc.c | 127 --- src/add-ons/accelerants/radeon/tv_out.c | 779 +++++++++++++++++ src/add-ons/accelerants/radeon/utils.c | 26 - src/add-ons/accelerants/radeon/utils.h | 25 - 49 files changed, 4080 insertions(+), 3558 deletions(-) create mode 100644 src/add-ons/accelerants/common/Jamfile rename src/add-ons/accelerants/{radeon => common}/ddc.c (76%) rename src/add-ons/accelerants/{radeon => common}/ddc_int.h (100%) rename src/add-ons/accelerants/{radeon/edid.c => common/decode_edid.c} (97%) rename src/add-ons/accelerants/{radeon => common}/dump_edid.c (100%) rename src/add-ons/accelerants/{radeon => common}/i2c.c (95%) create mode 100644 src/add-ons/accelerants/radeon/CP.h delete mode 100644 src/add-ons/accelerants/radeon/CPMicroCode.h delete mode 100644 src/add-ons/accelerants/radeon/ddc.h create mode 100644 src/add-ons/accelerants/radeon/driver_wrapper.c delete mode 100644 src/add-ons/accelerants/radeon/edid.h delete mode 100644 src/add-ons/accelerants/radeon/edid_raw.h delete mode 100644 src/add-ons/accelerants/radeon/engine_sync.c delete mode 100644 src/add-ons/accelerants/radeon/i2c.h delete mode 100644 src/add-ons/accelerants/radeon/log_coll.c delete mode 100644 src/add-ons/accelerants/radeon/log_coll.h delete mode 100644 src/add-ons/accelerants/radeon/log_dump.c delete mode 100644 src/add-ons/accelerants/radeon/log_dump.h delete mode 100644 src/add-ons/accelerants/radeon/log_enum.h delete mode 100644 src/add-ons/accelerants/radeon/log_names.h create mode 100644 src/add-ons/accelerants/radeon/monitor_detection.c create mode 100644 src/add-ons/accelerants/radeon/monitor_routing.c create mode 100644 src/add-ons/accelerants/radeon/palette.c delete mode 100644 src/add-ons/accelerants/radeon/radeonlog_dump.c delete mode 100644 src/add-ons/accelerants/radeon/test_ddc.c create mode 100644 src/add-ons/accelerants/radeon/tv_out.c delete mode 100644 src/add-ons/accelerants/radeon/utils.c delete mode 100644 src/add-ons/accelerants/radeon/utils.h diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile index edbbb08162..eee69023cf 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -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 ; diff --git a/src/add-ons/accelerants/common/Jamfile b/src/add-ons/accelerants/common/Jamfile new file mode 100644 index 0000000000..60ff3313c4 --- /dev/null +++ b/src/add-ons/accelerants/common/Jamfile @@ -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 +; diff --git a/src/add-ons/accelerants/radeon/ddc.c b/src/add-ons/accelerants/common/ddc.c similarity index 76% rename from src/add-ons/accelerants/radeon/ddc.c rename to src/add-ons/accelerants/common/ddc.c index 4b486c3caa..06bc5bf5b0 100644 --- a/src/add-ons/accelerants/radeon/ddc.c +++ b/src/add-ons/accelerants/common/ddc.c @@ -11,14 +11,13 @@ #include #include #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; diff --git a/src/add-ons/accelerants/radeon/ddc_int.h b/src/add-ons/accelerants/common/ddc_int.h similarity index 100% rename from src/add-ons/accelerants/radeon/ddc_int.h rename to src/add-ons/accelerants/common/ddc_int.h diff --git a/src/add-ons/accelerants/radeon/edid.c b/src/add-ons/accelerants/common/decode_edid.c similarity index 97% rename from src/add-ons/accelerants/radeon/edid.c rename to src/add-ons/accelerants/common/decode_edid.c index 09747a42eb..e2fd2b1349 100644 --- a/src/add-ons/accelerants/radeon/edid.c +++ b/src/add-ons/accelerants/common/decode_edid.c @@ -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; diff --git a/src/add-ons/accelerants/radeon/dump_edid.c b/src/add-ons/accelerants/common/dump_edid.c similarity index 100% rename from src/add-ons/accelerants/radeon/dump_edid.c rename to src/add-ons/accelerants/common/dump_edid.c diff --git a/src/add-ons/accelerants/radeon/i2c.c b/src/add-ons/accelerants/common/i2c.c similarity index 95% rename from src/add-ons/accelerants/radeon/i2c.c rename to src/add-ons/accelerants/common/i2c.c index 8bbd7aea58..1b5e973ddc 100644 --- a/src/add-ons/accelerants/radeon/i2c.c +++ b/src/add-ons/accelerants/common/i2c.c @@ -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; } diff --git a/src/add-ons/accelerants/radeon/Acceleration.c b/src/add-ons/accelerants/radeon/Acceleration.c index c04d1c8f28..1d01288769 100644 --- a/src/add-ons/accelerants/radeon/Acceleration.c +++ b/src/add-ons/accelerants/radeon/Acceleration.c @@ -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 ); +} diff --git a/src/add-ons/accelerants/radeon/CP.c b/src/add-ons/accelerants/radeon/CP.c index 3207691adf..7cc60ed796 100644 --- a/src/add-ons/accelerants/radeon/CP.c +++ b/src/add-ons/accelerants/radeon/CP.c @@ -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 +#include "CP.h" #include "log_coll.h" #include "log_enum.h" #include -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 ); + } } diff --git a/src/add-ons/accelerants/radeon/CP.h b/src/add-ons/accelerants/radeon/CP.h new file mode 100644 index 0000000000..e2cdc779c2 --- /dev/null +++ b/src/add-ons/accelerants/radeon/CP.h @@ -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); diff --git a/src/add-ons/accelerants/radeon/CPMicroCode.h b/src/add-ons/accelerants/radeon/CPMicroCode.h deleted file mode 100644 index f486ea096b..0000000000 --- a/src/add-ons/accelerants/radeon/CPMicroCode.h +++ /dev/null @@ -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 diff --git a/src/add-ons/accelerants/radeon/Cursor.c b/src/add-ons/accelerants/radeon/Cursor.c index dad8d093a5..ce00ecba94 100644 --- a/src/add-ons/accelerants/radeon/Cursor.c +++ b/src/add-ons/accelerants/radeon/Cursor.c @@ -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 ); } } diff --git a/src/add-ons/accelerants/radeon/EngineManagment.c b/src/add-ons/accelerants/radeon/EngineManagment.c index 53cd994c42..c572ad4d85 100644 --- a/src/add-ons/accelerants/radeon/EngineManagment.c +++ b/src/add-ons/accelerants/radeon/EngineManagment.c @@ -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; } diff --git a/src/add-ons/accelerants/radeon/GetAccelerantHook.c b/src/add-ons/accelerants/radeon/GetAccelerantHook.c index 903eeea9c6..816d3b59f9 100644 --- a/src/add-ons/accelerants/radeon/GetAccelerantHook.c +++ b/src/add-ons/accelerants/radeon/GetAccelerantHook.c @@ -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. diff --git a/src/add-ons/accelerants/radeon/GetModeInfo.c b/src/add-ons/accelerants/radeon/GetModeInfo.c index fe3e5aba96..ad60cdf44d 100644 --- a/src/add-ons/accelerants/radeon/GetModeInfo.c +++ b/src/add-ons/accelerants/radeon/GetModeInfo.c @@ -11,7 +11,6 @@ #include "radeon_accelerant.h" #include "GlobalData.h" #include "generic.h" -#include #include @@ -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; } diff --git a/src/add-ons/accelerants/radeon/GlobalData.h b/src/add-ons/accelerants/radeon/GlobalData.h index b754b1b8a0..ac3fadd933 100644 --- a/src/add-ons/accelerants/radeon/GlobalData.h +++ b/src/add-ons/accelerants/radeon/GlobalData.h @@ -10,6 +10,8 @@ #include "radeon_accelerant.h" #endif + +// the one and only we support extern accelerator_info *ai; diff --git a/src/add-ons/accelerants/radeon/InitAccelerant.c b/src/add-ons/accelerants/radeon/InitAccelerant.c index ebecb730d0..aa1b22a770 100644 --- a/src/add-ons/accelerants/radeon/InitAccelerant.c +++ b/src/add-ons/accelerants/radeon/InitAccelerant.c @@ -18,6 +18,7 @@ #include "fcntl.h" #include #include +#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; diff --git a/src/add-ons/accelerants/radeon/Jamfile b/src/add-ons/accelerants/radeon/Jamfile index 0a7ee155bc..d2f73ce0f1 100644 --- a/src/add-ons/accelerants/radeon/Jamfile +++ b/src/add-ons/accelerants/radeon/Jamfile @@ -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 ; diff --git a/src/add-ons/accelerants/radeon/ProposeDisplayMode.c b/src/add-ons/accelerants/radeon/ProposeDisplayMode.c index 961c386c02..494f318ec7 100644 --- a/src/add-ons/accelerants/radeon/ProposeDisplayMode.c +++ b/src/add-ons/accelerants/radeon/ProposeDisplayMode.c @@ -10,7 +10,6 @@ #include "radeon_accelerant.h" #include "generic.h" #include -#include #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 ); diff --git a/src/add-ons/accelerants/radeon/SetDisplayMode.c b/src/add-ons/accelerants/radeon/SetDisplayMode.c index 902caccc37..fcd5ea6bfa 100644 --- a/src/add-ons/accelerants/radeon/SetDisplayMode.c +++ b/src/add-ons/accelerants/radeon/SetDisplayMode.c @@ -23,34 +23,6 @@ #include -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] ); -} diff --git a/src/add-ons/accelerants/radeon/crtc.c b/src/add-ons/accelerants/radeon/crtc.c index ff0a03d6f3..bf41012899 100644 --- a/src/add-ons/accelerants/radeon/crtc.c +++ b/src/add-ons/accelerants/radeon/crtc.c @@ -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; +} diff --git a/src/add-ons/accelerants/radeon/ddc.h b/src/add-ons/accelerants/radeon/ddc.h deleted file mode 100644 index 5e8f7b3d56..0000000000 --- a/src/add-ons/accelerants/radeon/ddc.h +++ /dev/null @@ -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 diff --git a/src/add-ons/accelerants/radeon/dpms.c b/src/add-ons/accelerants/radeon/dpms.c index 43e2dff46a..332941e54c 100644 --- a/src/add-ons/accelerants/radeon/dpms.c +++ b/src/add-ons/accelerants/radeon/dpms.c @@ -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 ); +} diff --git a/src/add-ons/accelerants/radeon/driver_wrapper.c b/src/add-ons/accelerants/radeon/driver_wrapper.c new file mode 100644 index 0000000000..77b99d5025 --- /dev/null +++ b/src/add-ons/accelerants/radeon/driver_wrapper.c @@ -0,0 +1,78 @@ +/* + Copyright (c) 2003, Thomas Kurschel + + + Part of Radeon accelerant + + Kernel driver wrapper +*/ + +#include "radeon_accelerant.h" +#include + +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; +} diff --git a/src/add-ons/accelerants/radeon/edid.h b/src/add-ons/accelerants/radeon/edid.h deleted file mode 100644 index 3b0d038158..0000000000 --- a/src/add-ons/accelerants/radeon/edid.h +++ /dev/null @@ -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 diff --git a/src/add-ons/accelerants/radeon/edid_raw.h b/src/add-ons/accelerants/radeon/edid_raw.h deleted file mode 100644 index fc1ade055f..0000000000 --- a/src/add-ons/accelerants/radeon/edid_raw.h +++ /dev/null @@ -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 diff --git a/src/add-ons/accelerants/radeon/engine_sync.c b/src/add-ons/accelerants/radeon/engine_sync.c deleted file mode 100644 index ff19beab27..0000000000 --- a/src/add-ons/accelerants/radeon/engine_sync.c +++ /dev/null @@ -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 - -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; -} diff --git a/src/add-ons/accelerants/radeon/flat_panel.c b/src/add-ons/accelerants/radeon/flat_panel.c index 5c78a07c95..44139ec973 100644 --- a/src/add-ons/accelerants/radeon/flat_panel.c +++ b/src/add-ons/accelerants/radeon/flat_panel.c @@ -8,46 +8,54 @@ */ #include "radeon_accelerant.h" -#include #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 ); } diff --git a/src/add-ons/accelerants/radeon/i2c.h b/src/add-ons/accelerants/radeon/i2c.h deleted file mode 100644 index 17eee85661..0000000000 --- a/src/add-ons/accelerants/radeon/i2c.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (c) 2003, Thomas Kurschel - - - Part of DDC driver - - I2C protocoll -*/ - -#ifndef _I2C_H -#define _I2C_H - -#include - -// 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 with standard 100kHz bus timing -void i2c_get100k_timing( i2c_timing *timing ); - -// fill with standard 400kHz bus timing -// (as timing resolution is 1 microsecond, we cannot reach full speed!) -void i2c_get400k_timing( i2c_timing *timing ); - -#endif diff --git a/src/add-ons/accelerants/radeon/log_coll.c b/src/add-ons/accelerants/radeon/log_coll.c deleted file mode 100644 index 811e749e50..0000000000 --- a/src/add-ons/accelerants/radeon/log_coll.c +++ /dev/null @@ -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 -#include -#include -#include -#include "log_coll.h" -#include -#include - -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 diff --git a/src/add-ons/accelerants/radeon/log_coll.h b/src/add-ons/accelerants/radeon/log_coll.h deleted file mode 100644 index 3bbc3978eb..0000000000 --- a/src/add-ons/accelerants/radeon/log_coll.h +++ /dev/null @@ -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 - -// 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 diff --git a/src/add-ons/accelerants/radeon/log_dump.c b/src/add-ons/accelerants/radeon/log_dump.c deleted file mode 100644 index 3b574cf1ca..0000000000 --- a/src/add-ons/accelerants/radeon/log_dump.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (c) 2002, Thomas Kurschel - - - Part of Radeon driver - - Fast logger - functions to create dump -*/ - - -#include -#include - -#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 ); - } -} diff --git a/src/add-ons/accelerants/radeon/log_dump.h b/src/add-ons/accelerants/radeon/log_dump.h deleted file mode 100644 index bb2a775b91..0000000000 --- a/src/add-ons/accelerants/radeon/log_dump.h +++ /dev/null @@ -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 - -void log_printall( FILE *logfile, char *buffer, uint32 buffer_len ); - -#endif diff --git a/src/add-ons/accelerants/radeon/log_enum.h b/src/add-ons/accelerants/radeon/log_enum.h deleted file mode 100644 index 9b0aac938c..0000000000 --- a/src/add-ons/accelerants/radeon/log_enum.h +++ /dev/null @@ -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, -}; diff --git a/src/add-ons/accelerants/radeon/log_names.h b/src/add-ons/accelerants/radeon/log_names.h deleted file mode 100644 index ebc5b3a6f7..0000000000 --- a/src/add-ons/accelerants/radeon/log_names.h +++ /dev/null @@ -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", -}; diff --git a/src/add-ons/accelerants/radeon/monitor_detection.c b/src/add-ons/accelerants/radeon/monitor_detection.c new file mode 100644 index 0000000000..56b3e5a5dd --- /dev/null +++ b/src/add-ons/accelerants/radeon/monitor_detection.c @@ -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 + +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; +} diff --git a/src/add-ons/accelerants/radeon/monitor_routing.c b/src/add-ons/accelerants/radeon/monitor_routing.c new file mode 100644 index 0000000000..934ffbec91 --- /dev/null +++ b/src/add-ons/accelerants/radeon/monitor_routing.c @@ -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; +} diff --git a/src/add-ons/accelerants/radeon/multimon.c b/src/add-ons/accelerants/radeon/multimon.c index a97f52424b..97c8003deb 100644 --- a/src/add-ons/accelerants/radeon/multimon.c +++ b/src/add-ons/accelerants/radeon/multimon.c @@ -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 ); diff --git a/src/add-ons/accelerants/radeon/overlay.c b/src/add-ons/accelerants/radeon/overlay.c index aa2b2193f9..54c1a40004 100644 --- a/src/add-ons/accelerants/radeon/overlay.c +++ b/src/add-ons/accelerants/radeon/overlay.c @@ -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 #include - -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 ); diff --git a/src/add-ons/accelerants/radeon/overlay_management.c b/src/add-ons/accelerants/radeon/overlay_management.c index e539ab1c37..2ae3c67f92 100644 --- a/src/add-ons/accelerants/radeon/overlay_management.c +++ b/src/add-ons/accelerants/radeon/overlay_management.c @@ -15,16 +15,6 @@ #include #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 ) diff --git a/src/add-ons/accelerants/radeon/palette.c b/src/add-ons/accelerants/radeon/palette.c new file mode 100644 index 0000000000..1a4fe3bc8a --- /dev/null +++ b/src/add-ons/accelerants/radeon/palette.c @@ -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(); +} diff --git a/src/add-ons/accelerants/radeon/pll.c b/src/add-ons/accelerants/radeon/pll.c index 63aef83ead..568c7a4811 100644 --- a/src/add-ons/accelerants/radeon/pll.c +++ b/src/add-ons/accelerants/radeon/pll.c @@ -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 -// 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 ); } diff --git a/src/add-ons/accelerants/radeon/radeon_accelerant.h b/src/add-ons/accelerants/radeon/radeon_accelerant.h index ee31812aad..ee5d1bd8e7 100644 --- a/src/add-ons/accelerants/radeon/radeon_accelerant.h +++ b/src/add-ons/accelerants/radeon/radeon_accelerant.h @@ -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 } diff --git a/src/add-ons/accelerants/radeon/radeonlog_dump.c b/src/add-ons/accelerants/radeon/radeonlog_dump.c deleted file mode 100644 index 6ca4f77b2f..0000000000 --- a/src/add-ons/accelerants/radeon/radeonlog_dump.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright (c) 2002, Thomas Kurschel - - - Part of Radeon driver - - Fast logger - application to write log file -*/ - - -#include -#include -#include -#include -#include "log_dump.h" -#include -#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; -} diff --git a/src/add-ons/accelerants/radeon/settings.cpp b/src/add-ons/accelerants/radeon/settings.cpp index 9f667156f5..79ccad6d13 100644 --- a/src/add-ons/accelerants/radeon/settings.cpp +++ b/src/add-ons/accelerants/radeon/settings.cpp @@ -21,22 +21,19 @@ #include "generic.h" #include "GlobalData.h" -#ifdef ENABLE_SETTINGS_FILE #include #include #include -#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 } diff --git a/src/add-ons/accelerants/radeon/test_ddc.c b/src/add-ons/accelerants/radeon/test_ddc.c deleted file mode 100644 index e839ee1f16..0000000000 --- a/src/add-ons/accelerants/radeon/test_ddc.c +++ /dev/null @@ -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 -#include -#include -#include -#include - -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; -} diff --git a/src/add-ons/accelerants/radeon/tv_out.c b/src/add-ons/accelerants/radeon/tv_out.c new file mode 100644 index 0000000000..d0b8ab3858 --- /dev/null +++ b/src/add-ons/accelerants/radeon/tv_out.c @@ -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 + } +} diff --git a/src/add-ons/accelerants/radeon/utils.c b/src/add-ons/accelerants/radeon/utils.c deleted file mode 100644 index 05071e2755..0000000000 --- a/src/add-ons/accelerants/radeon/utils.c +++ /dev/null @@ -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; -} diff --git a/src/add-ons/accelerants/radeon/utils.h b/src/add-ons/accelerants/radeon/utils.h deleted file mode 100644 index 193a3a12f4..0000000000 --- a/src/add-ons/accelerants/radeon/utils.h +++ /dev/null @@ -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