⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modetbl.cpp

📁 SM501基于ARMV4/ARMV4I平台
💻 CPP
📖 第 1 页 / 共 3 页
字号:

#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 + -