Copyright (c) 2002-2004, Thomas Kurschel
Part of Radeon accelerant
Everything concerning getting/testing display modes
*/
#include "radeon_accelerant.h"
#include "generic.h"
#include <string.h>
#include "GlobalData.h"
#include "crtc_regs.h"
#include "utils.h"
#include "set_mode.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
#define MODE_FLAGS (B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS | B_SUPPORTS_OVERLAYS)
static const display_mode base_mode_list[] = {
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS},
{ { 25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS},
{ { 26720, 720, 736, 808, 896, 480, 481, 484, 497, B_POSITIVE_VSYNC}, B_CMAP8, 720, 480, 0, 0, MODE_FLAGS},
{ { 26570, 720, 736, 808, 896, 576, 577, 580, 593, B_POSITIVE_VSYNC}, B_CMAP8, 720, 576, 0, 0, MODE_FLAGS},
{ { 28460, 768, 784, 864, 960, 576, 577, 580, 593, B_POSITIVE_VSYNC}, B_CMAP8, 768, 576, 0, 0, MODE_FLAGS},
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 108000, 1280, 1376, 1488, 1800, 960, 961, 964, 1000, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 148500, 1280, 1344, 1504, 1728, 960, 961, 964, 1011, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS},
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS},
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS},
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS},
{ { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS},
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 84490, 1360, 1392, 1712, 1744, 768, 783, 791, 807, T_POSITIVE_SYNC}, B_CMAP8, 1360, 768, 0, 0, MODE_FLAGS},
{ { 84970, 1368, 1400, 1720, 1752, 768, 783, 791, 807, T_POSITIVE_SYNC}, B_CMAP8, 1368, 768, 0, 0, MODE_FLAGS},
{ { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS},
{ { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS},
{ { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS},
{ { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS},
{ { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS},
{ { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS},
{ { 193160, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS},
{ { 74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, T_POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS},
};
bool Radeon_GetFormat( int space, int *format, int *bpp )
{
switch( space ) {
case B_CMAP8: *format = 2; *bpp = 1; break;
case B_RGB15_LITTLE: *format = 3; *bpp = 2; break;
case B_RGB16_LITTLE: *format = 4; *bpp = 2; break;
case B_RGB24_LITTLE: *format = 5; *bpp = 3; break;
case B_RGB32_LITTLE: *format = 6; *bpp = 4; break;
default:
SHOW_ERROR( 1, "Unsupported color space (%d)", space );
return false;
}
return true;
}
#define H_DISPLAY_2REG( a ) ((a) / 8 - 1)
#define H_DISPLAY_2PIX( a ) (((a) + 1) * 8)
#define H_TOTAL_2REG( a ) ((a) / 8 - 1)
#define H_TOTAL_2PIX( a ) (((a) + 1) * 8)
#define H_SSTART_2REG( a ) ((a) - 8 + h_sync_fudge)
#define H_SSTART_2PIX( a ) ((a) + 8 - h_sync_fudge)
#define H_SWID_2REG( a ) ((a) / 8)
#define H_SWID_2PIX( a ) ((a) * 8)
#define V_2REG( a ) ((a) - 1)
#define V_2PIX( a ) ((a) + 1)
Validate a target display mode is both
a) a valid display mode for this device and
b) falls between the contraints imposed by "low" and "high"
If the mode is not (or cannot) be made valid for this device, return B_ERROR.
If a valid mode can be constructed, but it does not fall within the limits,
return B_BAD_VALUE.
If the mode is both valid AND falls within the limits, return B_OK.
*/
static status_t
Radeon_ProposeDisplayMode(shared_info *si, crtc_info *crtc,
general_pll_info *pll, display_mode *target,
const display_mode *low, const display_mode *high)
{
status_t result = B_OK;
uint64 target_refresh;
bool want_same_width, want_same_height;
int format, bpp;
uint32 row_bytes;
int eff_virtual_width;
fp_info *flatpanel = &si->flatpanels[crtc->flatpanel_port];
SHOW_FLOW( 4, "CRTC %d, DVI %d", (crtc == &si->crtc[0]) ? 0 : 1, crtc->flatpanel_port );
SHOW_FLOW( 4, "X %d, virtX %d", target->timing.h_display, target->virtual_width);
SHOW_FLOW( 4, "fpRes %dx%d", flatpanel->panel_xres, flatpanel->panel_yres);
if (target->timing.h_total * target->timing.v_total == 0)
return B_BAD_VALUE;
target_refresh =
(((uint64)target->timing.pixel_clock * 1000) << FIX_SHIFT) /
((uint64)target->timing.h_total * target->timing.v_total);
want_same_width = target->timing.h_display == target->virtual_width;
want_same_height = target->timing.v_display == target->virtual_height;
if( !Radeon_GetFormat( target->space, &format, &bpp ))
return B_ERROR;
if( (crtc->chosen_displays & (dd_lvds | dd_dvi)) != 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;
}
if( (crtc->chosen_displays & dd_dvi_ext) != 0 ) {
SHOW_FLOW0( 4, "external (secondary) DVI cannot support non-native resolutions" );
if( ( target->timing.h_display != flatpanel->panel_xres ) ||
( target->timing.v_display != flatpanel->panel_yres ) )
return B_ERROR;
}
// 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;
}
*/
{
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( crtc, 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;
if( h_display < 320 )
h_display = 320;
if( h_display > H_DISPLAY_2PIX( RADEON_CRTC_H_DISP >> RADEON_CRTC_H_DISP_SHIFT ) )
h_display = H_DISPLAY_2PIX( RADEON_CRTC_H_DISP >> RADEON_CRTC_H_DISP_SHIFT );
h_display = H_DISPLAY_2PIX( H_DISPLAY_2REG( h_display ));
if( h_sync_start < h_display + 2*8 )
h_sync_start = h_display + 2*8;
if( h_sync_start > H_SSTART_2PIX( RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX ) - 4*8 )
h_sync_start = H_SSTART_2PIX( RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX ) - 4*8;
if( h_sync_wid < H_SWID_2PIX( 3 ))
h_sync_wid = H_SWID_2PIX( 3 );
if( h_sync_wid > H_SWID_2PIX( RADEON_CRTC_H_SYNC_WID >> RADEON_CRTC_H_SYNC_WID_SHIFT ) )
h_sync_wid = H_SWID_2PIX( RADEON_CRTC_H_SYNC_WID >> RADEON_CRTC_H_SYNC_WID_SHIFT );
h_sync_wid = H_SWID_2PIX( H_SWID_2REG( h_sync_wid ));
if( h_total < h_sync_start + h_sync_wid + 1*8 + 7 )
h_total = h_sync_start + h_sync_wid + 1*8 + 7;
if( h_total > H_TOTAL_2PIX( RADEON_CRTC_H_TOTAL ) ) {
h_total = H_TOTAL_2PIX( RADEON_CRTC_H_TOTAL );
h_sync_wid = min( h_sync_wid, h_total - h_sync_start );
h_sync_wid = H_SWID_2PIX( H_SWID_2REG( h_sync_wid ));
}
h_total = H_TOTAL_2PIX( H_TOTAL_2REG( h_total ));
target->timing.h_display = h_display;
target->timing.h_sync_start = h_sync_start;
target->timing.h_sync_end = h_sync_start + h_sync_wid;
target->timing.h_total = h_total;
}
if( target->timing.h_display < low->timing.h_display ||
target->timing.h_display > high->timing.h_display ||
target->timing.h_sync_start < low->timing.h_sync_start ||
target->timing.h_sync_start > high->timing.h_sync_start ||
target->timing.h_sync_end < low->timing.h_sync_end ||
target->timing.h_sync_end > high->timing.h_sync_end ||
target->timing.h_total < low->timing.h_total ||
target->timing.h_total > high->timing.h_total)
{
SHOW_FLOW0( 4, "out of horizontal limits" );
result = B_BAD_VALUE;
}
{
int v_display, v_sync_start, v_sync_wid, v_total;
v_display = target->timing.v_display;
v_sync_start = target->timing.v_sync_start;
v_sync_wid = target->timing.v_sync_end - target->timing.v_sync_start;
v_total = target->timing.v_total;
if( v_display < 200 )
v_display = 200;
if( v_display > V_2PIX(RADEON_CRTC_V_DISP >> RADEON_CRTC_V_DISP_SHIFT) - 5)
v_display = V_2PIX(RADEON_CRTC_V_DISP >> RADEON_CRTC_V_DISP_SHIFT) - 5;
if( v_sync_start < v_display + 1 )
v_sync_start = v_display + 1;
if( v_sync_start > V_2PIX(RADEON_CRTC_V_SYNC_STRT) - 4)
v_sync_start = V_2PIX(RADEON_CRTC_V_SYNC_STRT) - 4;
if( v_sync_wid < 2 )
v_sync_wid = 2;
if( v_sync_wid > (RADEON_CRTC_V_SYNC_WID >> RADEON_CRTC_V_SYNC_WID_SHIFT))
v_sync_wid = (RADEON_CRTC_V_SYNC_WID >> RADEON_CRTC_V_SYNC_WID_SHIFT);
if( v_total < v_sync_start + v_sync_wid + 1 )
v_total = v_sync_start + v_sync_wid + 1;
if( v_total > V_2PIX( RADEON_CRTC_V_TOTAL ) ) {
v_total = V_2PIX( RADEON_CRTC_V_TOTAL );
v_sync_wid = min( v_sync_wid, v_total - v_sync_start - 4 );
}
target->timing.v_display = v_display;
target->timing.v_sync_start = v_sync_start;
target->timing.v_sync_end = v_sync_start + v_sync_wid;
target->timing.v_total = v_total;
}
if( target->timing.v_display < low->timing.v_display ||
target->timing.v_display > high->timing.v_display ||
target->timing.v_sync_start < low->timing.v_sync_start ||
target->timing.v_sync_start > high->timing.v_sync_start ||
target->timing.v_sync_end < low->timing.v_sync_end ||
target->timing.v_sync_end > high->timing.v_sync_end ||
target->timing.v_total < low->timing.v_total ||
target->timing.v_total > high->timing.v_total )
{
SHOW_FLOW0( 4, "out of vertical limits" );
result = B_BAD_VALUE;
}
target->timing.pixel_clock =
((uint64)target_refresh / 1000 * target->timing.h_total * target->timing.v_total + FIX_SCALE / 2)
>> FIX_SHIFT;
if( target->timing.pixel_clock / 10 > pll->max_pll_freq ||
target->timing.pixel_clock / 10 * 12 < pll->min_pll_freq )
{
SHOW_ERROR( 4, "pixel_clock (%ld) out of range (%d, %d)", target->timing.pixel_clock,
pll->max_pll_freq * 10, pll->min_pll_freq / 12 );
return B_ERROR;
}
if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display;
if (target->virtual_width > 1024*8)
target->virtual_width = 1024*8;
if (target->virtual_width < low->virtual_width ||
target->virtual_width > high->virtual_width )
{
SHOW_FLOW0( 4, "out of virtual horizontal limits" );
result = B_BAD_VALUE;
}
eff_virtual_width = Radeon_RoundVWidth( target->virtual_height, bpp );
row_bytes = eff_virtual_width * bpp;
if ((row_bytes * target->virtual_height) > si->memory[mt_local].size - 1024 )
target->virtual_height = (si->memory[mt_local].size - 1024) / row_bytes;
if (target->virtual_height < target->timing.v_display) {
SHOW_ERROR( 4, "not enough memory for this mode (could show only %d of %d lines)",
target->virtual_height, target->timing.v_display );
return B_ERROR;
}
if (target->virtual_height < low->virtual_height ||
target->virtual_height > high->virtual_height )
{
SHOW_FLOW0( 4, "out of virtual vertical limits" );
result = B_BAD_VALUE;
}
return result;
}
uint32 ACCELERANT_MODE_COUNT( void )
{
return ai->si->mode_count;
}
status_t GET_MODE_LIST( display_mode *dm )
{
memcpy( dm, ai->mode_list, ai->si->mode_count * sizeof(display_mode) );
return B_OK;
}
static const color_space spaces[4] = {
B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE
};
static void checkAndAddMode( accelerator_info *ai, const display_mode *mode, bool ignore_timing )
{
shared_info *si = ai->si;
uint i;
display_mode low, high;
uint32 pix_clk_range;
display_mode *dst;
if( ignore_timing ) {
for( i = 0; i < si->mode_count; ++i ) {
if( ai->mode_list[i].timing.h_display == mode->timing.h_display &&
ai->mode_list[i].timing.v_display == mode->timing.v_display &&
ai->mode_list[i].virtual_width == mode->virtual_width &&
ai->mode_list[i].virtual_height == mode->virtual_height )
return;
}
}
low = high = *mode;
pix_clk_range = low.timing.pixel_clock >> 5;
low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range;
if( ignore_timing ) {
low.timing.h_total = 0;
low.timing.h_sync_start = 0;
low.timing.h_sync_end = 0;
low.timing.v_total = 0;
low.timing.v_sync_start = 0;
low.timing.v_sync_end = 0;
high.timing.h_total = 0xffff;
high.timing.h_sync_start = 0xffff;
high.timing.h_sync_end = 0xffff;
high.timing.v_total = 0xffff;
high.timing.v_sync_start = 0xffff;
high.timing.v_sync_end = 0xffff;
}
dst = &ai->mode_list[si->mode_count];
for( i = 0; i < (sizeof(spaces) / sizeof(color_space)); i++ ) {
*dst = *mode;
dst->space = low.space = high.space = spaces[i];
if( Radeon_ProposeDisplayMode( si, &si->crtc[0],
&si->pll, dst, &low, &high ) == B_OK )
{
si->mode_count++;
++dst;
} else {
*dst = *mode;
dst->space = spaces[i];
if( Radeon_ProposeDisplayMode( si, &si->crtc[1],
&si->pll, dst, &low, &high ) == B_OK )
{
si->mode_count++;
++dst;
} else
SHOW_FLOW( 4, "%ld, %ld not supported", dst->virtual_width, dst->virtual_height );
}
}
}
static void checkAndAddMultiMode( accelerator_info *ai, const display_mode *mode,
bool ignore_timing )
{
display_mode wide_mode;
SHOW_FLOW( 4, "%ld, %ld", mode->virtual_width, mode->virtual_height );
checkAndAddMode( ai, mode, ignore_timing );
wide_mode = *mode;
wide_mode.virtual_width *= 2;
wide_mode.flags |= B_SCROLL;
checkAndAddMode( ai, &wide_mode, ignore_timing );
wide_mode = *mode;
wide_mode.virtual_height *= 2;
wide_mode.flags |= B_SCROLL;
checkAndAddMode( ai, &wide_mode, ignore_timing );
}
static void addFPMode( accelerator_info *ai )
{
shared_info *si = ai->si;
fp_info *fp_info = &si->flatpanels[0];
if( (ai->vc->connected_displays & (dd_dvi | dd_dvi_ext | dd_lvds)) != 0 ) {
display_mode mode;
SHOW_FLOW0( 2, "" );
mode.virtual_width = mode.timing.h_display = fp_info->panel_xres;
mode.virtual_height = mode.timing.v_display = fp_info->panel_yres;
mode.timing.h_total = mode.timing.h_display + fp_info->h_blank;
mode.timing.h_sync_start = mode.timing.h_display + fp_info->h_over_plus;
mode.timing.h_sync_end = mode.timing.h_sync_start + fp_info->h_sync_width;
mode.timing.v_total = mode.timing.v_display + fp_info->v_blank;
mode.timing.v_sync_start = mode.timing.v_display + fp_info->v_over_plus;
mode.timing.v_sync_end = mode.timing.v_sync_start + fp_info->v_sync_width;
mode.timing.pixel_clock = fp_info->dot_clock;
if( mode.timing.pixel_clock == 0 ) {
mode.timing.pixel_clock =
((uint32)mode.timing.h_total * mode.timing.v_total * 60) / 1000;
}
mode.flags = MODE_FLAGS;
mode.h_display_start = 0;
mode.v_display_start = 0;
SHOW_FLOW( 2, "H: %4d %4d %4d %4d (v=%4d)",
mode.timing.h_display, mode.timing.h_sync_start,
mode.timing.h_sync_end, mode.timing.h_total, mode.virtual_width );
SHOW_FLOW( 2, "V: %4d %4d %4d %4d (h=%4d)",
mode.timing.v_display, mode.timing.v_sync_start,
mode.timing.v_sync_end, mode.timing.v_total, mode.virtual_height );
SHOW_FLOW( 2, "clk: %ld", mode.timing.pixel_clock );
checkAndAddMultiMode( ai, &mode, true );
}
}
status_t Radeon_CreateModeList( shared_info *si )
{
size_t max_size;
uint i;
uint max_num_modes;
max_num_modes = ((sizeof( base_mode_list ) / sizeof( base_mode_list[0] ) + 1) * 4 * 3);
max_size = (max_num_modes * sizeof(display_mode) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
si->mode_list_area = create_area("Radeon accelerant mode info",
(void **)&ai->mode_list, B_ANY_ADDRESS,
max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if( si->mode_list_area < B_OK )
return si->mode_list_area;
si->mode_count = 0;
for( i = 0; i < sizeof( base_mode_list ) / sizeof( base_mode_list[0] ); i++ )
checkAndAddMultiMode( ai, &base_mode_list[i], false );
addFPMode( ai );
ai->mode_list_area = si->mode_list_area;
return B_OK;
}
status_t
PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low,
const display_mode *high)
{
virtual_card *vc = ai->vc;
shared_info *si = ai->si;
status_t result1, result2;
bool isTunneled;
status_t result;
display_mode tmp_target;
result = Radeon_CheckMultiMonTunnel( vc, target, low, high, &isTunneled );
if( isTunneled )
return result;
tmp_target = *target;
Radeon_DetectMultiMode( vc, &tmp_target );
Radeon_DetectDisplays( ai);
Radeon_SetupDefaultMonitorRouting(
ai, Radeon_DifferentPorts( &tmp_target ), vc->use_laptop_panel );
Radeon_DetectMultiMode( vc, target );
Radeon_VerifyMultiMode( vc, si, target );
SHOW_FLOW0( 2, "wished:" );
SHOW_FLOW( 2, "H: %4d %4d %4d %4d (v=%4d)",
target->timing.h_display, target->timing.h_sync_start,
target->timing.h_sync_end, target->timing.h_total, target->virtual_width );
SHOW_FLOW( 2, "V: %4d %4d %4d %4d (h=%4d)",
target->timing.v_display, target->timing.v_sync_start,
target->timing.v_sync_end, target->timing.v_total, target->virtual_height );
SHOW_FLOW( 2, "clk: %ld", target->timing.pixel_clock );
result1 = Radeon_ProposeDisplayMode( si, &si->crtc[0],
&si->pll, target, low, high );
if( result1 == B_ERROR )
return B_ERROR;
if( Radeon_NeedsSecondPort( target )) {
result2 = Radeon_ProposeDisplayMode( si, &si->crtc[1],
&si->pll, target, low, high );
if( result2 == B_ERROR )
return B_ERROR;
} else {
result2 = B_OK;
}
SHOW_INFO0( 2, "got:" );
SHOW_INFO( 2, "H: %4d %4d %4d %4d (v=%4d)",
target->timing.h_display, target->timing.h_sync_start,
target->timing.h_sync_end, target->timing.h_total, target->virtual_width );
SHOW_INFO( 2, "V: %4d %4d %4d %4d (h=%4d)",
target->timing.v_display, target->timing.v_sync_start,
target->timing.v_sync_end, target->timing.v_total, target->virtual_height );
SHOW_INFO( 2, "clk: %ld", target->timing.pixel_clock );
Radeon_HideMultiMode( vc, target );
if( result1 == B_OK && result2 == B_OK )
return B_OK;
else
return B_BAD_VALUE;
}