📄 modetbl.cpp
字号:
#include "precomp.h"
//#include <stdio.h>
//#include "modetbl.h"
//#include "smi.h"
//#include "panel.h"
//#include "power.h"
unsigned long SMI::rev()
{
static unsigned long dwRev = 0x00;
if (dwRev == 0x00)
{
if (DEVICEID == CHIPID_SM501)
dwRev = (REVISION) | 0x0A;
else
dwRev = (REVISION);
}
return dwRev;
}
// Perform a rounded division.
long round(long num, long denom)
{
/* n / d + 1 / 2 = (2n + d) / 2d */
return (2 * num + denom) / (2 * denom);
}
// Find the best clock.
long findClock(long requested_clock, clock_select_t *clock, display_t display,
long test_clock)
{
long mclk;
int divider, shift;
long best_diff = 999999999;
if (test_clock == 0)
{
// Try 288MHz and 336MHz clocks.
for (mclk = 288000000; mclk <= 336000000; mclk += 48000000)
{
// For CRT, try dividers 1 and 3, for panel, try divider 5 as well.
for (divider = 1; divider <= (display == PANEL ? 5 : 3);
divider += 2)
{
// Try all 8 shift values.
for (shift = 0; shift < 8; shift++)
{
// Calculate difference with requested clock.
long diff = round(mclk, divider << shift) - requested_clock;
if (diff < 0)
{
diff = -diff;
}
// If the difference is less than the current, use it.
if (diff < best_diff)
{
// Store best difference.
best_diff = diff;
// Store clock values.
clock->mclk = mclk;
clock->divider = divider;
clock->shift = shift;
}
}
}
}
}
else
{
// For CRT, try dividers 1 and 3, for panel, try divider 5 as well.
for (divider = 1; divider <= (display == PANEL ? 5 : 3); divider += 2)
{
// Try all 8 shift values.
for (shift = 0; shift < 8; shift++)
{
// Calculate difference with requested clock.
long diff = round(test_clock, divider << shift)
- requested_clock;
if (diff < 0)
{
diff = -diff;
}
// If the difference is less than the current, use it.
if (diff < best_diff)
{
// Store best difference.
best_diff = diff;
// Store clock values.
clock->mclk = test_clock;
clock->divider = divider;
clock->shift = shift;
}
}
}
}
// Save test clock for later.
clock->test_clock = test_clock;
// Return best clock.
return clock->mclk / (clock->divider << clock->shift);
}
// Find the requested mode in the mode table.
mode_table_t *findMode(mode_table_t *mode_table, int width, int height,
int refresh_rate)
{
// Walk the entire mode table.
while (mode_table->pixel_clock != 0)
{
// If this mode matches the requested mode, return it!
if ((mode_table->horizontal_display_end == width)
&& (mode_table->vertical_display_end == height)
&& (mode_table->vertical_frequency == refresh_rate))
{
return(mode_table);
}
// Next entry in the mode table.
mode_table++;
}
// No mode found.
return(NULL);
}
// Convert the VESA timing into Voyager timing.
void adjustMode(mode_table_t *vesaMode, mode_table_t *mode, display_t display,
long test_clock)
{
long blank_width, sync_start, sync_width, vesa_horizontal_frequency, vesa_vertical_frequency;
clock_select_t clock;
// Calculate the VESA line and screen frequencies.
vesa_horizontal_frequency = round(vesaMode->pixel_clock,
vesaMode->horizontal_total);
vesa_vertical_frequency = round(vesa_horizontal_frequency,
vesaMode->vertical_total);
// Calculate the sync percentages of the VESA mode.
blank_width = vesaMode->horizontal_total
- vesaMode->horizontal_display_end;
sync_start = round((vesaMode->horizontal_sync_start -
vesaMode->horizontal_display_end) * 100, blank_width);
sync_width = round(vesaMode->horizontal_sync_width * 100, blank_width);
// Copy VESA mode into Voyager mode.
*mode = *vesaMode;
// Find the best pixel clock.
mode->pixel_clock = findClock(vesaMode->pixel_clock * 2, &clock, display,
test_clock);
// Divide them back - Patch by TC 2003/03/12
mode->pixel_clock = mode->pixel_clock / 2;
// Calculate the horizontal total based on the pixel clock and VESA line
// frequency.
mode->horizontal_total = round(mode->pixel_clock,
vesa_horizontal_frequency);
// Calculate the sync start and width based on the VESA percentages.
blank_width = mode->horizontal_total - mode->horizontal_display_end;
mode->horizontal_sync_start = mode->horizontal_display_end
+ round(blank_width * sync_start, 100);
mode->horizontal_sync_width = round(blank_width * sync_width, 100);
// Calculate the line and screen frequencies.
mode->horizontal_frequency = round(mode->pixel_clock,
mode->horizontal_total);
mode->vertical_frequency = round(mode->horizontal_frequency,
mode->vertical_total);
}
// Fill the register structure.
void setModeRegisters(reg_table_t *register_table, mode_table_t *mode,
display_t display, int bpp, long test_clock)
{
clock_select_t clock = {0,0,0,0};
// Calculate the clock register values.
findClock(mode->pixel_clock * 2, &clock, display, test_clock);
if (display == PANEL)
{
// Set clock value for panel.
register_table->clock
= (clock.mclk == 288000000
? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_SELECT, 288)
: FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_SELECT, 336))
| (clock.divider == 1
? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 1)
: (clock.divider == 3
? FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 3)
: FIELD_SET(0, CURRENT_POWER_CLOCK, P2XCLK_DIVIDER, 5)))
| FIELD_VALUE(0, CURRENT_POWER_CLOCK, P2XCLK_SHIFT, clock.shift);
// Set control register value.
register_table->control
// Force panel sync plorities to negative 11/05/03
= FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW)
| FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW)
/* = (mode->vertical_sync_polarity == POSITIVE
? FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)
: FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))
| (mode->horizontal_sync_polarity == POSITIVE
? FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)
: FIELD_SET(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))
*/
| FIELD_SET(0, PANEL_DISPLAY_CTRL, TIMING, ENABLE)
| FIELD_SET(0, PANEL_DISPLAY_CTRL, PLANE, ENABLE)
| (bpp == 8
? FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 8)
: (bpp == 16
? FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 16)
: FIELD_SET(0, PANEL_DISPLAY_CTRL, FORMAT, 32)));
// Set timing registers.
register_table->horizontal_total
= FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL,
mode->horizontal_total - 1)
| FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END,
mode->horizontal_display_end - 1);
register_table->horizontal_sync
= FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH,
mode->horizontal_sync_width)
| FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START,
mode->horizontal_sync_start - 1);
register_table->vertical_total
= FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL,
mode->vertical_total - 1)
| FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END,
mode->vertical_display_end - 1);
register_table->vertical_sync
= FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT,
mode->vertical_sync_height)
| FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START,
mode->vertical_sync_start - 1);
}
else
{
// Set clock value for CRT.
register_table->clock
= (clock.mclk == 288000000
? FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_SELECT, 288)
: FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_SELECT, 336))
| (clock.divider == 1
? FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_DIVIDER, 1)
: FIELD_SET(0, CURRENT_POWER_CLOCK, V2XCLK_DIVIDER, 3))
| FIELD_VALUE(0, CURRENT_POWER_CLOCK, V2XCLK_SHIFT, clock.shift);
// Set control register value.
register_table->control
= (mode->vertical_sync_polarity == POSITIVE
? FIELD_SET(0, CRT_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)
: FIELD_SET(0, CRT_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))
| (mode->horizontal_sync_polarity == POSITIVE
? FIELD_SET(0, CRT_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)
: FIELD_SET(0, CRT_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))
| FIELD_SET(0, CRT_DISPLAY_CTRL, SELECT, CRT)
| FIELD_SET(0, CRT_DISPLAY_CTRL, TIMING, ENABLE)
| FIELD_SET(0, CRT_DISPLAY_CTRL, PLANE, ENABLE)
| (bpp == 8
? FIELD_SET(0, CRT_DISPLAY_CTRL, FORMAT, 8)
: (bpp == 16
? FIELD_SET(0, CRT_DISPLAY_CTRL, FORMAT, 16)
: FIELD_SET(0, CRT_DISPLAY_CTRL, FORMAT, 32)));
// Set timing registers.
register_table->horizontal_total
= FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, TOTAL,
mode->horizontal_total - 1)
| FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, DISPLAY_END,
mode->horizontal_display_end - 1);
register_table->horizontal_sync
= FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH,
mode->horizontal_sync_width)
| FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, START,
mode->horizontal_sync_start - 1);
register_table->vertical_total
= FIELD_VALUE(0, CRT_VERTICAL_TOTAL, TOTAL,
mode->vertical_total - 1)
| FIELD_VALUE(0, CRT_VERTICAL_TOTAL, DISPLAY_END,
mode->vertical_display_end - 1);
register_table->vertical_sync
= FIELD_VALUE(0, CRT_VERTICAL_SYNC, HEIGHT,
mode->vertical_sync_height)
| FIELD_VALUE(0, CRT_VERTICAL_SYNC, START,
mode->vertical_sync_start - 1);
}
// Calculate frame buffer width and height.
register_table->fb_width = mode->horizontal_display_end * (bpp / 8);
register_table->width = mode->horizontal_display_end;
register_table->height = mode->vertical_display_end;
// Save display type.
register_table->display = display;
}
// Program the mode with the registers specified.
void SMI::programMode(reg_table_t *register_table)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -