#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)
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;
}
{
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;
}